[gnome-initial-setup/shell/4765: 335/362] Use keyboard page design from GNOME 3.14.0



commit f45938524d7018e4a05181a89f0b99e0e3cf23e7
Author: Juan A. Suarez Romero <jasuarez igalia com>
Date:   Mon Feb 2 12:18:27 2015 +0100

    Use keyboard page design from GNOME 3.14.0
    
    This new design helps to select only one keyboard layout during the
    first boot experience.
    
    [endlessm/eos-shell#3364]

 gnome-initial-setup/pages/keyboard/Makefile.am     |    2 +
 .../pages/keyboard/cc-common-language.c            |  325 ++++
 .../pages/keyboard/cc-common-language.h            |   36 +
 gnome-initial-setup/pages/keyboard/cc-ibus-utils.c |    8 +-
 gnome-initial-setup/pages/keyboard/cc-ibus-utils.h |    4 +-
 .../pages/keyboard/cc-input-chooser.c              | 1661 ++++++++------------
 .../pages/keyboard/cc-input-chooser.h              |   52 +-
 gnome-initial-setup/pages/keyboard/cc-util.c       |  105 ++
 gnome-initial-setup/pages/keyboard/cc-util.h       |   28 +
 .../pages/keyboard/gis-keyboard-page.c             | 1195 ++-------------
 .../pages/keyboard/gis-keyboard-page.h             |    3 +-
 .../pages/keyboard/gis-keyboard-page.ui            |  297 +---
 .../pages/keyboard/input-chooser.ui                |   92 +-
 13 files changed, 1385 insertions(+), 2423 deletions(-)
---
diff --git a/gnome-initial-setup/pages/keyboard/Makefile.am b/gnome-initial-setup/pages/keyboard/Makefile.am
index 28b3fbd..545a8de 100644
--- a/gnome-initial-setup/pages/keyboard/Makefile.am
+++ b/gnome-initial-setup/pages/keyboard/Makefile.am
@@ -17,10 +17,12 @@ BUILT_SOURCES += keyboard-resources.c keyboard-resources.h
 
 libgiskeyboard_la_SOURCES =                            \
        cc-input-chooser.c cc-input-chooser.h           \
+       cc-common-language.c cc-common-language.h       \
        cc-ibus-utils.c cc-ibus-utils.h                 \
        cc-keyboard-detector.c cc-keyboard-detector.h   \
        cc-keyboard-query.c cc-keyboard-query.h         \
        cc-key-row.c cc-key-row.h                       \
+       cc-util.c cc-util.h                             \
        gis-keyboard-page.c gis-keyboard-page.h         \
        $(BUILT_SOURCES)
 
diff --git a/gnome-initial-setup/pages/keyboard/cc-common-language.c 
b/gnome-initial-setup/pages/keyboard/cc-common-language.c
new file mode 100644
index 0000000..c1d1399
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-common-language.c
@@ -0,0 +1,325 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009-2010  Red Hat, Inc,
+ *
+ * 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 2 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/>.
+ *
+ * Written by: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <fontconfig/fontconfig.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-languages.h>
+
+#include "cc-common-language.h"
+
+static char *get_lang_for_user_object_path (const char *path);
+
+gboolean
+cc_common_language_has_font (const gchar *locale)
+{
+        const FcCharSet *charset;
+        FcPattern       *pattern;
+        FcObjectSet     *object_set;
+        FcFontSet       *font_set;
+        gchar           *language_code;
+        gboolean         is_displayable;
+
+        is_displayable = FALSE;
+        pattern = NULL;
+        object_set = NULL;
+        font_set = NULL;
+
+        if (!gnome_parse_locale (locale, &language_code, NULL, NULL, NULL))
+                return FALSE;
+
+        charset = FcLangGetCharSet ((FcChar8 *) language_code);
+        if (!charset) {
+                /* fontconfig does not know about this language */
+                is_displayable = TRUE;
+        }
+        else {
+                /* see if any fonts support rendering it */
+                pattern = FcPatternBuild (NULL, FC_LANG, FcTypeString, language_code, NULL);
+
+                if (pattern == NULL)
+                        goto done;
+
+                object_set = FcObjectSetCreate ();
+
+                if (object_set == NULL)
+                        goto done;
+
+                font_set = FcFontList (NULL, pattern, object_set);
+
+                if (font_set == NULL)
+                        goto done;
+
+                is_displayable = (font_set->nfont > 0);
+        }
+
+ done:
+        if (font_set != NULL)
+                FcFontSetDestroy (font_set);
+
+        if (object_set != NULL)
+                FcObjectSetDestroy (object_set);
+
+        if (pattern != NULL)
+                FcPatternDestroy (pattern);
+
+        g_free (language_code);
+
+        return is_displayable;
+}
+
+gchar *
+cc_common_language_get_current_language (void)
+{
+        gchar *language;
+        char *path;
+        const gchar *locale;
+
+       path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", getuid ());
+        language = get_lang_for_user_object_path (path);
+        g_free (path);
+        if (language != NULL && *language != '\0')
+                return language;
+
+        locale = (const gchar *) setlocale (LC_MESSAGES, NULL);
+        if (locale)
+                language = gnome_normalize_locale (locale);
+        else
+                language = NULL;
+
+        return language;
+}
+
+static gboolean
+user_language_has_translations (const char *locale)
+{
+        char *name, *language_code, *territory_code;
+        gboolean ret;
+
+        gnome_parse_locale (locale,
+                            &language_code,
+                            &territory_code,
+                            NULL, NULL);
+        name = g_strdup_printf ("%s%s%s",
+                                language_code,
+                                territory_code != NULL? "_" : "",
+                                territory_code != NULL? territory_code : "");
+        g_free (language_code);
+        g_free (territory_code);
+        ret = gnome_language_has_translations (name);
+        g_free (name);
+
+        return ret;
+}
+
+static char *
+get_lang_for_user_object_path (const char *path)
+{
+       GError *error = NULL;
+       GDBusProxy *user;
+       GVariant *props;
+       char *lang;
+
+       user = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+                                             G_DBUS_PROXY_FLAGS_NONE,
+                                             NULL,
+                                             "org.freedesktop.Accounts",
+                                             path,
+                                             "org.freedesktop.Accounts.User",
+                                             NULL,
+                                             &error);
+       if (user == NULL) {
+               g_warning ("Failed to get proxy for user '%s': %s",
+                          path, error->message);
+               g_error_free (error);
+               return NULL;
+       }
+       props = g_dbus_proxy_get_cached_property (user, "Language");
+       lang = g_variant_dup_string (props, NULL);
+
+       g_variant_unref (props);
+       g_object_unref (user);
+       return lang;
+}
+
+static void
+add_other_users_language (GHashTable *ht)
+{
+        GVariant *variant;
+        GVariantIter *vi;
+        GError *error = NULL;
+        const char *str;
+        GDBusProxy *proxy;
+
+        proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+                                               G_DBUS_PROXY_FLAGS_NONE,
+                                               NULL,
+                                               "org.freedesktop.Accounts",
+                                               "/org/freedesktop/Accounts",
+                                               "org.freedesktop.Accounts",
+                                               NULL,
+                                               NULL);
+
+        if (proxy == NULL)
+                return;
+
+        variant = g_dbus_proxy_call_sync (proxy,
+                                          "ListCachedUsers",
+                                          NULL,
+                                          G_DBUS_CALL_FLAGS_NONE,
+                                          -1,
+                                          NULL,
+                                          &error);
+        if (variant == NULL) {
+                g_warning ("Failed to list existing users: %s", error->message);
+                g_error_free (error);
+                g_object_unref (proxy);
+                return;
+        }
+        g_variant_get (variant, "(ao)", &vi);
+        while (g_variant_iter_loop (vi, "o", &str)) {
+                char *lang;
+                char *name;
+                char *language;
+
+                lang = get_lang_for_user_object_path (str);
+                if (lang != NULL && *lang != '\0' &&
+                    cc_common_language_has_font (lang) &&
+                    user_language_has_translations (lang)) {
+                        name = gnome_normalize_locale (lang);
+                        if (!g_hash_table_lookup (ht, name)) {
+                                language = gnome_get_language_from_locale (name, NULL);
+                                g_hash_table_insert (ht, name, language);
+                        }
+                        else {
+                                g_free (name);
+                        }
+                }
+                g_free (lang);
+        }
+        g_variant_iter_free (vi);
+        g_variant_unref (variant);
+
+        g_object_unref (proxy);
+}
+
+static void
+insert_language_internal (GHashTable *ht,
+                          const char *lang)
+{
+        gboolean has_translations;
+        char *label_own_lang;
+        char *label_current_lang;
+        char *label_untranslated;
+        char *key;
+
+        has_translations = gnome_language_has_translations (lang);
+        if (!has_translations) {
+                char *lang_code = g_strndup (lang, 2);
+                has_translations = gnome_language_has_translations (lang_code);
+                g_free (lang_code);
+
+                if (!has_translations)
+                        return;
+        }
+
+        g_debug ("We have translations for %s", lang);
+
+        key = g_strdup (lang);
+
+        label_own_lang = gnome_get_language_from_locale (key, key);
+        label_current_lang = gnome_get_language_from_locale (key, NULL);
+        label_untranslated = gnome_get_language_from_locale (key, "C");
+
+        /* We don't have a translation for the label in
+         * its own language? */
+        if (g_strcmp0 (label_own_lang, label_untranslated) == 0) {
+                if (g_strcmp0 (label_current_lang, label_untranslated) == 0)
+                        g_hash_table_insert (ht, key, g_strdup (label_untranslated));
+                else
+                        g_hash_table_insert (ht, key, g_strdup (label_current_lang));
+        } else {
+                g_hash_table_insert (ht, key, g_strdup (label_own_lang));
+        }
+
+        g_free (label_own_lang);
+        g_free (label_current_lang);
+        g_free (label_untranslated);
+}
+
+static void
+insert_language (GHashTable *ht,
+                 const char *lang)
+{
+        char *utf8_variant = g_strconcat (lang, ".utf8", NULL);
+        insert_language_internal (ht, lang);
+        insert_language_internal (ht, utf8_variant);
+        g_free (utf8_variant);
+}
+
+static void
+insert_user_languages (GHashTable *ht)
+{
+        char *name;
+        char *language;
+
+        /* Add the languages used by other users on the system */
+        add_other_users_language (ht);
+
+        /* Add current locale */
+        name = cc_common_language_get_current_language ();
+        if (g_hash_table_lookup (ht, name) == NULL) {
+                language = gnome_get_language_from_locale (name, NULL);
+                g_hash_table_insert (ht, name, language);
+        } else {
+                g_free (name);
+        }
+}
+
+GHashTable *
+cc_common_language_get_initial_languages (void)
+{
+        GHashTable *ht;
+
+        ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+        insert_language (ht, "en_US");
+        insert_language (ht, "en_GB");
+        insert_language (ht, "de_DE");
+        insert_language (ht, "fr_FR");
+        insert_language (ht, "es_ES");
+        insert_language (ht, "zh_CN");
+        insert_language (ht, "ja_JP");
+        insert_language (ht, "ru_RU");
+        insert_language (ht, "ar_EG");
+
+        insert_user_languages (ht);
+
+        return ht;
+}
diff --git a/gnome-initial-setup/pages/keyboard/cc-common-language.h 
b/gnome-initial-setup/pages/keyboard/cc-common-language.h
new file mode 100644
index 0000000..7f32cab
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-common-language.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009-2010  Red Hat, Inc,
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ * Written by: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __CC_COMMON_LANGUAGE_H__
+#define __CC_COMMON_LANGUAGE_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+gboolean cc_common_language_has_font                (const gchar  *locale);
+gchar   *cc_common_language_get_current_language    (void);
+GHashTable *cc_common_language_get_initial_languages   (void);
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-initial-setup/pages/keyboard/cc-ibus-utils.c 
b/gnome-initial-setup/pages/keyboard/cc-ibus-utils.c
index 54f9fb7..424c69e 100644
--- a/gnome-initial-setup/pages/keyboard/cc-ibus-utils.c
+++ b/gnome-initial-setup/pages/keyboard/cc-ibus-utils.c
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -28,11 +26,15 @@ engine_get_display_name (IBusEngineDesc *engine_desc)
         const gchar *name;
         const gchar *language_code;
         const gchar *language;
+        const gchar *textdomain;
         gchar *display_name;
 
         name = ibus_engine_desc_get_longname (engine_desc);
         language_code = ibus_engine_desc_get_language (engine_desc);
         language = ibus_get_language_name (language_code);
+        textdomain = ibus_engine_desc_get_textdomain (engine_desc);
+        if (*textdomain != '\0' && *name != '\0')
+                name = g_dgettext (textdomain, name);
         display_name = g_strdup_printf ("%s (%s)", language, name);
 
         return display_name;
diff --git a/gnome-initial-setup/pages/keyboard/cc-ibus-utils.h 
b/gnome-initial-setup/pages/keyboard/cc-ibus-utils.h
index bcd0c68..da3d996 100644
--- a/gnome-initial-setup/pages/keyboard/cc-ibus-utils.h
+++ b/gnome-initial-setup/pages/keyboard/cc-ibus-utils.h
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __GIS_IBUS_UTILS_H__
diff --git a/gnome-initial-setup/pages/keyboard/cc-input-chooser.c 
b/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
index d96f21d..83aa4ce 100644
--- a/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
+++ b/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
@@ -12,1202 +12,855 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre mecheye net>
+ *     Matthias Clasen <mclasen redhat com>
  */
 
-#include <config.h>
+#include "config.h"
+#include "cc-input-chooser.h"
+
 #include <locale.h>
 #include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <gtk/gtk.h>
 
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 #include <libgnome-desktop/gnome-languages.h>
-
-#include <egg-list-box.h>
-
-#include <../language/cc-common-language.h>
-#include <../language/cc-util.h>
-#include "cc-input-chooser.h"
+#include <libgnome-desktop/gnome-xkb-info.h>
 
 #ifdef HAVE_IBUS
 #include <ibus.h>
 #include "cc-ibus-utils.h"
-#endif  /* HAVE_IBUS */
+#endif
+
+#include "cc-common-language.h"
+#include "cc-util.h"
+
+#include <glib-object.h>
 
 #define INPUT_SOURCE_TYPE_XKB "xkb"
 #define INPUT_SOURCE_TYPE_IBUS "ibus"
 
-#define ARROW_NEXT "go-next-symbolic"
-#define ARROW_PREV "go-previous-symbolic"
+#define MIN_ROWS 6
 
-#define MAIN_WINDOW_WIDTH_RATIO 0.60
+struct _CcInputChooserPrivate
+{
+        GtkWidget *filter_entry;
+        GtkWidget *input_list;
+       GHashTable *inputs;
 
-typedef enum {
-  ROW_TRAVEL_DIRECTION_NONE,
-  ROW_TRAVEL_DIRECTION_FORWARD,
-  ROW_TRAVEL_DIRECTION_BACKWARD
-} RowTravelDirection;
+        GtkWidget *scrolled_window;
+        GtkWidget *no_results;
+        GtkWidget *more_item;
 
-typedef enum {
-  ROW_LABEL_POSITION_START,
-  ROW_LABEL_POSITION_CENTER,
-  ROW_LABEL_POSITION_END
-} RowLabelPosition;
+        gboolean showing_extra;
+       gchar *locale;
+        gchar *id;
+       gchar *type;
+       GnomeXkbInfo *xkb_info;
+#ifdef HAVE_IBUS
+        IBusBus *ibus;
+        GHashTable *ibus_engines;
+        GCancellable *ibus_cancellable;
+#endif
+};
+typedef struct _CcInputChooserPrivate CcInputChooserPrivate;
+G_DEFINE_TYPE_WITH_PRIVATE (CcInputChooser, cc_input_chooser, GTK_TYPE_BOX);
+
+enum {
+        PROP_0,
+        PROP_SHOWING_EXTRA,
+        PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST];
+
+enum {
+       CHANGED,
+        CONFIRM,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
 
 typedef struct {
-  /* Not owned */
-  GtkWidget *add_button;
-  GtkWidget *filter_entry;
-  GtkWidget *list;
-  GtkWidget *scrolledwindow;
-  GtkAdjustment *adjustment;
-  GnomeXkbInfo *xkb_info;
-  GHashTable *ibus_engines;
-
-  /* Owned */
-  GtkWidget *more_item;
-  GtkWidget *no_results;
-  GHashTable *locales;
-  GHashTable *locales_by_language;
-  gboolean showing_extra;
-  gchar **filter_words;
-} CcInputChooserPrivate;
-
-#define GET_PRIVATE(chooser) ((CcInputChooserPrivate *) g_object_get_data (G_OBJECT (chooser), "private"))
-#define WID(name) ((GtkWidget *) gtk_builder_get_object (builder, name))
+        GtkWidget *box;
+        GtkWidget *label;
+        GtkWidget *checkmark;
 
-typedef struct {
-  gchar *id;
-  gchar *name;
-  gchar *unaccented_name;
-  gchar *untranslated_name;
-  GtkWidget *default_input_source_widget;
-  GtkWidget *locale_widget;
-  GtkWidget *back_widget;
-  GHashTable *layout_widgets_by_id;
-  GHashTable *engine_widgets_by_id;
-} LocaleInfo;
+        gchar *id;
+        gchar *type;
+        gchar *name;
+        gboolean is_extra;
+} InputWidget;
 
-static void
-locale_info_free (gpointer data)
+static InputWidget *
+get_input_widget (GtkWidget *widget)
 {
-  LocaleInfo *info = data;
-
-  g_free (info->id);
-  g_free (info->name);
-  g_free (info->unaccented_name);
-  g_free (info->untranslated_name);
-  g_object_unref (info->default_input_source_widget);
-  g_object_unref (info->locale_widget);
-  g_object_unref (info->back_widget);
-  g_hash_table_destroy (info->layout_widgets_by_id);
-  g_hash_table_destroy (info->engine_widgets_by_id);
-  g_free (info);
+        return g_object_get_data (G_OBJECT (widget), "input-widget");
 }
 
-static void
-set_row_widget_margins (GtkWidget *widget)
+static GtkWidget *
+padded_label_new (char *text)
 {
-  gtk_widget_set_margin_left (widget, 20);
-  gtk_widget_set_margin_right (widget, 20);
-  gtk_widget_set_margin_top (widget, 6);
-  gtk_widget_set_margin_bottom (widget, 6);
+        GtkWidget *widget;
+        widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+        gtk_widget_set_halign (widget, GTK_ALIGN_CENTER);
+        gtk_widget_set_margin_top (widget, 10);
+        gtk_widget_set_margin_bottom (widget, 10);
+        gtk_box_pack_start (GTK_BOX (widget), gtk_label_new (text), FALSE, FALSE, 0);
+        return widget;
 }
 
-static GtkWidget *
-padded_label_new (const gchar        *text,
-                  RowLabelPosition    position,
-                  RowTravelDirection  direction,
-                  gboolean            dim_label)
+static void
+input_widget_free (gpointer data)
 {
-  GtkWidget *widget;
-  GtkWidget *label;
-  GtkWidget *arrow;
-  gdouble alignment;
-  gboolean rtl;
-
-  rtl = (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL);
-
-  if (position == ROW_LABEL_POSITION_START)
-    alignment = 0.0;
-  else if (position == ROW_LABEL_POSITION_CENTER)
-    alignment = 0.5;
-  else
-    alignment = 1.0;
-
-  widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-
-  if (direction == ROW_TRAVEL_DIRECTION_BACKWARD)
-    {
-      arrow = gtk_image_new_from_icon_name (rtl ? ARROW_NEXT : ARROW_PREV,
-                                            GTK_ICON_SIZE_MENU);
-      gtk_box_pack_start (GTK_BOX (widget), arrow, FALSE, TRUE, 0);
-    }
-
-  label = gtk_label_new (text);
-  gtk_misc_set_alignment (GTK_MISC (label), alignment, 0.5);
-  set_row_widget_margins (label);
-  gtk_box_pack_start (GTK_BOX (widget), label, TRUE, TRUE, 0);
-  if (dim_label)
-    gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
-
-  if (direction == ROW_TRAVEL_DIRECTION_FORWARD)
-    {
-      arrow = gtk_image_new_from_icon_name (rtl ? ARROW_PREV : ARROW_NEXT,
-                                            GTK_ICON_SIZE_MENU);
-      gtk_box_pack_start (GTK_BOX (widget), arrow, FALSE, TRUE, 0);
-    }
-
-  return widget;
+        InputWidget *widget = data;
+
+        g_free (widget->id);
+        g_free (widget->type);
+        g_free (widget->name);
+        g_free (widget);
 }
 
-static GtkWidget *
-more_widget_new (void)
-{
-  GtkWidget *widget;
-  GtkWidget *arrow;
+static gboolean
+get_layout (CcInputChooser *chooser,
+            const gchar    *type,
+           const gchar    *id,
+           const gchar   **layout,
+            const gchar   **variant)
+{
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+
+       if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
+               gnome_xkb_info_get_layout_info (priv->xkb_info,
+                                               id, NULL, NULL,
+                                               layout, variant);
+                return TRUE;
+        }
+#ifdef HAVE_IBUS
+       if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
+                IBusEngineDesc *engine_desc = NULL;
 
-  widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-  gtk_widget_set_tooltip_text (widget, _("More…"));
+               if (priv->ibus_engines)
+                       engine_desc = g_hash_table_lookup (priv->ibus_engines, id);
 
-  arrow = gtk_image_new_from_icon_name ("view-more-symbolic", GTK_ICON_SIZE_MENU);
-  gtk_style_context_add_class (gtk_widget_get_style_context (arrow), "dim-label");
-  set_row_widget_margins (arrow);
-  gtk_misc_set_alignment (GTK_MISC (arrow), 0.5, 0.5);
-  gtk_box_pack_start (GTK_BOX (widget), arrow, TRUE, TRUE, 0);
+               if (!engine_desc)
+                        return FALSE;
 
-  return widget;
+                *layout = ibus_engine_desc_get_layout (engine_desc);
+                *variant = "";
+                return TRUE;
+       }
+#endif
+        g_assert_not_reached ();
+       return FALSE;
 }
 
-static GtkWidget *
-no_results_widget_new (void)
+static gboolean
+preview_cb (GtkLabel       *label,
+           const gchar    *uri,
+           CcInputChooser *chooser)
 {
-  return padded_label_new (_("No input sources found"), ROW_LABEL_POSITION_CENTER, 
ROW_TRAVEL_DIRECTION_NONE, TRUE);
-}
+       GtkWidget *row;
+       InputWidget *widget;
+       const gchar *layout;
+       const gchar *variant;
+       gchar *commandline;
 
-static GtkWidget *
-back_widget_new (const gchar *text)
-{
-  return padded_label_new (text, ROW_LABEL_POSITION_CENTER, ROW_TRAVEL_DIRECTION_BACKWARD, TRUE);
-}
+       row = gtk_widget_get_parent (GTK_WIDGET (label));
+       widget = get_input_widget (row);
 
-static GtkWidget *
-locale_widget_new (const gchar *text)
-{
-  return padded_label_new (text, ROW_LABEL_POSITION_CENTER, ROW_TRAVEL_DIRECTION_NONE, FALSE);
-}
+       if (!get_layout (chooser, widget->type, widget->id, &layout, &variant))
+               return TRUE;
 
-static GtkWidget *
-locale_separator_widget_new (const gchar *text)
-{
-  GtkWidget *widget;
-
-  widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-  gtk_box_pack_start (GTK_BOX (widget),
-                      gtk_separator_new (GTK_ORIENTATION_HORIZONTAL),
-                      FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (widget),
-                      padded_label_new (text, ROW_LABEL_POSITION_CENTER, ROW_TRAVEL_DIRECTION_NONE, TRUE),
-                      FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (widget),
-                      gtk_separator_new (GTK_ORIENTATION_HORIZONTAL),
-                      FALSE, FALSE, 0);
-  return widget;
+       if (variant[0])
+               commandline = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"", layout, variant);
+       else
+               commandline = g_strdup_printf ("gkbd-keyboard-display -l %s", layout);
+       g_spawn_command_line_async (commandline, NULL);
+       g_free (commandline);
+
+       return TRUE;
 }
 
 static GtkWidget *
-input_source_widget_new (GtkWidget   *chooser,
-                         const gchar *type,
-                         const gchar *id)
-{
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  GtkWidget *widget = NULL;
-
-  if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB))
-    {
-      const gchar *display_name;
-
-      gnome_xkb_info_get_layout_info (priv->xkb_info, id, &display_name, NULL, NULL, NULL);
-
-      widget = padded_label_new (display_name,
-                                 ROW_LABEL_POSITION_START,
-                                 ROW_TRAVEL_DIRECTION_NONE,
-                                 FALSE);
-      g_object_set_data (G_OBJECT (widget), "name", (gpointer) display_name);
-      g_object_set_data_full (G_OBJECT (widget), "unaccented-name",
-                              cc_util_normalize_casefold_and_unaccent (display_name), g_free);
-    }
-  else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS))
-    {
+input_widget_new (CcInputChooser *chooser,
+                  const char *type,
+                  const char *id,
+                   gboolean    is_extra)
+{
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+       GtkWidget *label;
+        InputWidget *widget = g_new0 (InputWidget, 1);
+       const gchar *name;
+       gchar *text;
+
+       if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
+               gnome_xkb_info_get_layout_info (priv->xkb_info, id, &name, NULL, NULL, NULL);
+       }
 #ifdef HAVE_IBUS
-      gchar *display_name;
-      GtkWidget *image;
-
-      display_name = engine_get_display_name (g_hash_table_lookup (priv->ibus_engines, id));
-
-      widget = padded_label_new (display_name,
-                                 ROW_LABEL_POSITION_START,
-                                 ROW_TRAVEL_DIRECTION_NONE,
-                                 FALSE);
-      image = gtk_image_new_from_icon_name ("system-run-symbolic", GTK_ICON_SIZE_MENU);
-      set_row_widget_margins (image);
-      gtk_style_context_add_class (gtk_widget_get_style_context (image), "dim-label");
-      gtk_box_pack_start (GTK_BOX (widget), image, FALSE, TRUE, 0);
-
-      g_object_set_data_full (G_OBJECT (widget), "name", display_name, g_free);
-      g_object_set_data_full (G_OBJECT (widget), "unaccented-name",
-                              cc_util_normalize_casefold_and_unaccent (display_name), g_free);
-#else
-      widget = NULL;
-#endif  /* HAVE_IBUS */
-    }
-
-  if (widget)
-    {
-      g_object_set_data (G_OBJECT (widget), "type", (gpointer) type);
-      g_object_set_data (G_OBJECT (widget), "id", (gpointer) id);
-    }
-
-  return widget;
+        else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
+                if (priv->ibus_engines)
+                        name = engine_get_display_name (g_hash_table_lookup (priv->ibus_engines, id));
+                else
+                        name = id;
+       }
+#endif
+       else {
+               name = "ERROR";
+       }
+
+        widget->id = g_strdup (id);
+       widget->type = g_strdup (type);
+       widget->name = g_strdup (name);
+       widget->is_extra = is_extra;
+
+       widget->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+       gtk_widget_set_halign (widget->box, GTK_ALIGN_FILL);
+       gtk_widget_set_margin_top (widget->box, 10);
+       gtk_widget_set_margin_bottom (widget->box, 10);
+       gtk_widget_set_margin_start (widget->box, 10);
+       gtk_widget_set_margin_end (widget->box, 10);
+       widget->label = gtk_label_new (name);
+       gtk_misc_set_alignment (GTK_MISC (widget->label), 0, 0.5);
+        gtk_label_set_ellipsize (GTK_LABEL (widget->label), PANGO_ELLIPSIZE_END);
+        gtk_label_set_max_width_chars (GTK_LABEL (widget->label), 40);
+       gtk_label_set_width_chars (GTK_LABEL (widget->label), 40);
+       gtk_box_pack_start (GTK_BOX (widget->box), widget->label, FALSE, FALSE, 0);
+       widget->checkmark = gtk_image_new_from_icon_name ("object-select-symbolic", GTK_ICON_SIZE_MENU);
+       gtk_box_pack_start (GTK_BOX (widget->box), widget->checkmark, TRUE, TRUE, 0);
+       gtk_widget_set_margin_start (widget->checkmark, 10);
+       gtk_widget_set_margin_end (widget->checkmark, 10);
+       gtk_widget_set_halign (widget->box, GTK_ALIGN_START);
+
+       text = g_strdup_printf ("<a href='preview'>%s</a>", _("Preview"));
+       label = gtk_label_new ("");
+       gtk_label_set_markup (GTK_LABEL (label), text);
+       g_free (text);
+       g_signal_connect (label, "activate-link",
+                         G_CALLBACK (preview_cb), chooser);
+       gtk_box_pack_start (GTK_BOX (widget->box), label, TRUE, TRUE, 0);
+
+       gtk_widget_show_all (widget->box);
+
+       g_object_set_data_full (G_OBJECT (widget->box), "input-widget", widget,
+                               input_widget_free);
+
+       return widget->box;
 }
 
 static void
-remove_all_children (GtkContainer *container)
+sync_checkmark (GtkWidget *row,
+                gpointer   user_data)
 {
-  GList *list, *l;
+       CcInputChooser *chooser = user_data;
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        GtkWidget *child;
+        InputWidget *widget;
+        gboolean should_be_visible;
 
-  list = gtk_container_get_children (container);
-  for (l = list; l; l = l->next)
-    gtk_container_remove (container, (GtkWidget *) l->data);
-  g_list_free (list);
-}
+        child = gtk_bin_get_child (GTK_BIN (row));
+        widget = get_input_widget (child);
 
-static void
-set_fixed_size (GtkWidget *chooser)
-{
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  GtkPolicyType policy;
-  gint width, height;
-
-  gtk_scrolled_window_get_policy (GTK_SCROLLED_WINDOW (priv->scrolledwindow), &policy, NULL);
-  if (policy == GTK_POLICY_AUTOMATIC)
-    return;
-
-  /* Don't let it automatically get wider than the main GIS window nor
-     get taller than the initial height */
-  gtk_window_get_size (gtk_window_get_transient_for (GTK_WINDOW (chooser)),
-                       &width, NULL);
-  gtk_window_get_size (GTK_WINDOW (chooser), NULL, &height);
-  gtk_widget_set_size_request (chooser, width * MAIN_WINDOW_WIDTH_RATIO, height);
-
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolledwindow),
-                                  GTK_POLICY_AUTOMATIC,
-                                  GTK_POLICY_AUTOMATIC);
-}
+        if (widget == NULL)
+                return;
 
-static void
-update_separator (GtkWidget **separator,
-                  GtkWidget  *child,
-                  GtkWidget  *before,
-                  gpointer    user_data)
-{
-  if (*separator && !GTK_IS_SEPARATOR (*separator))
-    {
-      gtk_widget_destroy (*separator);
-      *separator = NULL;
-    }
-
-  if (*separator == NULL)
-    {
-      *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-      g_object_ref_sink (*separator);
-      gtk_widget_show (*separator);
-    }
+       if (priv->id == NULL || priv->type == NULL)
+               should_be_visible = FALSE;
+       else
+               should_be_visible = g_str_equal (widget->id, priv->id) && g_str_equal (widget->type, 
priv->type);
+        gtk_widget_set_opacity (widget->checkmark, should_be_visible ? 1.0 : 0.0);
 }
 
 static void
-add_input_source_widgets_for_locale (GtkWidget  *chooser,
-                                     LocaleInfo *info)
+sync_all_checkmarks (CcInputChooser *chooser)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  GtkWidget *widget;
-  GHashTableIter iter;
-  const gchar *id;
-
-  if (info->default_input_source_widget)
-    gtk_container_add (GTK_CONTAINER (priv->list), info->default_input_source_widget);
-
-  g_hash_table_iter_init (&iter, info->layout_widgets_by_id);
-  while (g_hash_table_iter_next (&iter, (gpointer *) &id, (gpointer *) &widget))
-    gtk_container_add (GTK_CONTAINER (priv->list), widget);
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
 
-  g_hash_table_iter_init (&iter, info->engine_widgets_by_id);
-  while (g_hash_table_iter_next (&iter, (gpointer *) &id, (gpointer *) &widget))
-    gtk_container_add (GTK_CONTAINER (priv->list), widget);
+        gtk_container_foreach (GTK_CONTAINER (priv->input_list),
+                               sync_checkmark, chooser);
 }
 
-static void
-show_input_sources_for_locale (GtkWidget   *chooser,
-                               LocaleInfo  *info)
+static GtkWidget *
+more_widget_new (void)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
+        GtkWidget *widget;
+        GtkWidget *arrow;
 
-  set_fixed_size (chooser);
+        widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+        gtk_widget_set_tooltip_text (widget, _("More…"));
 
-  remove_all_children (GTK_CONTAINER (priv->list));
+        arrow = gtk_image_new_from_icon_name ("view-more-symbolic", GTK_ICON_SIZE_MENU);
+        gtk_style_context_add_class (gtk_widget_get_style_context (arrow), "dim-label");
+        gtk_widget_set_margin_top (widget, 10);
+        gtk_widget_set_margin_bottom (widget, 10);
+        gtk_misc_set_alignment (GTK_MISC (arrow), 0.5, 0.5);
+        gtk_box_pack_start (GTK_BOX (widget), arrow, TRUE, TRUE, 0);
+       gtk_widget_show_all (widget);
 
-  if (!info->back_widget)
-    {
-      info->back_widget = g_object_ref_sink (back_widget_new (info->name));
-      g_object_set_data (G_OBJECT (info->back_widget), "back", GINT_TO_POINTER (TRUE));
-      g_object_set_data (G_OBJECT (info->back_widget), "locale-info", info);
-    }
-  gtk_container_add (GTK_CONTAINER (priv->list), info->back_widget);
-
-  add_input_source_widgets_for_locale (chooser, info);
+        return widget;
+}
 
-  gtk_widget_show_all (priv->list);
+static GtkWidget *
+no_results_widget_new (void)
+{
+        GtkWidget *widget;
 
-  gtk_adjustment_set_value (priv->adjustment,
-                            gtk_adjustment_get_lower (priv->adjustment));
-  egg_list_box_set_separator_funcs (EGG_LIST_BOX (priv->list), update_separator, NULL, NULL);
-  egg_list_box_refilter (EGG_LIST_BOX (priv->list));
-  egg_list_box_set_selection_mode (EGG_LIST_BOX (priv->list), GTK_SELECTION_SINGLE);
+        /* Translators: a search for input methods or keyboard layouts
+         * did not yield any results
+         */
+        widget = padded_label_new (_("No inputs found"));
+        gtk_widget_set_sensitive (widget, FALSE);
+       gtk_widget_show_all (widget);
+        return widget;
+}
 
-  if (gtk_widget_is_visible (priv->filter_entry))
-    gtk_widget_grab_focus (priv->filter_entry);
+static void
+add_rows_to_list (CcInputChooser  *chooser,
+                 GList            *list,
+                 const gchar      *type,
+                 const gchar      *default_id)
+{
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+       const gchar *id;
+       GtkWidget *widget;
+       gboolean is_extra;
+       gchar *key;
+
+       for (; list; list = list->next) {
+               id = (const gchar *) list->data;
+
+               if (g_strcmp0 (id, default_id) == 0)
+                       continue;
+
+               key = g_strdup_printf ("%s::%s", type, id);
+               if (g_hash_table_contains (priv->inputs, key)) {
+                       g_free (key);
+                       continue;
+               }
+               g_hash_table_add (priv->inputs, key);
+
+               if (g_hash_table_size (priv->inputs) > MIN_ROWS)
+                       is_extra = TRUE;
+               else
+                       is_extra = FALSE;
+               widget = input_widget_new (chooser, type, id, is_extra);
+               gtk_container_add (GTK_CONTAINER (priv->input_list), widget);
+       }
 }
 
-static gboolean
-is_current_locale (const gchar *locale)
+static void
+add_row_to_list (CcInputChooser *chooser,
+                const gchar     *type,
+                const gchar     *id)
 {
-  return g_strcmp0 (setlocale (LC_CTYPE, NULL), locale) == 0;
+       GList tmp = { 0 };
+       tmp.data = (gpointer)id;
+       add_rows_to_list (chooser, &tmp, type, NULL);
 }
 
 static void
-show_locale_widgets (GtkWidget *chooser)
+get_locale_infos (CcInputChooser *chooser)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  GHashTable *initial = NULL;
-  LocaleInfo *info;
-  GHashTableIter iter;
-
-  remove_all_children (GTK_CONTAINER (priv->list));
-
-  if (!priv->showing_extra)
-    initial = cc_common_language_get_initial_languages ();
-
-  g_hash_table_iter_init (&iter, priv->locales);
-  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
-    {
-      if (!info->default_input_source_widget &&
-          !g_hash_table_size (info->layout_widgets_by_id) &&
-          !g_hash_table_size (info->engine_widgets_by_id))
-        continue;
-
-      if (!info->locale_widget)
-        {
-          info->locale_widget = g_object_ref_sink (locale_widget_new (info->name));
-          g_object_set_data (G_OBJECT (info->locale_widget), "locale-info", info);
-
-          if (!priv->showing_extra &&
-              !g_hash_table_contains (initial, info->id) &&
-              !is_current_locale (info->id))
-            g_object_set_data (G_OBJECT (info->locale_widget), "is-extra", GINT_TO_POINTER (TRUE));
-        }
-      gtk_container_add (GTK_CONTAINER (priv->list), info->locale_widget);
-    }
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+       const gchar *type, *id;
+       gchar *lang, *country;
+       GList *list;
 
-  gtk_container_add (GTK_CONTAINER (priv->list), priv->more_item);
+       if (gnome_get_input_source_from_locale (priv->locale, &type, &id)) {
+                add_row_to_list (chooser, type, id);
+               if (!priv->id) {
+                       priv->id = g_strdup (id);
+                       priv->type = g_strdup (type);
+               }
+       }
 
-  gtk_widget_show_all (priv->list);
+       if (!gnome_parse_locale (priv->locale, &lang, &country, NULL, NULL))
+               goto out;
 
-  gtk_adjustment_set_value (priv->adjustment,
-                            gtk_adjustment_get_lower (priv->adjustment));
-  egg_list_box_set_separator_funcs (EGG_LIST_BOX (priv->list), update_separator, NULL, NULL);
-  egg_list_box_refilter (EGG_LIST_BOX (priv->list));
-  egg_list_box_set_selection_mode (EGG_LIST_BOX (priv->list), GTK_SELECTION_NONE);
+       list = gnome_xkb_info_get_layouts_for_language (priv->xkb_info, lang);
+       add_rows_to_list (chooser, list, INPUT_SOURCE_TYPE_XKB, id);
+       g_list_free (list);
 
-  if (gtk_widget_is_visible (priv->filter_entry))
-    gtk_widget_grab_focus (priv->filter_entry);
+       list = gnome_xkb_info_get_layouts_for_country (priv->xkb_info, country);
+       add_rows_to_list (chooser, list, INPUT_SOURCE_TYPE_XKB, id);
+       g_list_free (list);
 
-  if (!priv->showing_extra)
-    g_hash_table_destroy (initial);
+       list = gnome_xkb_info_get_all_layouts (priv->xkb_info);
+       add_rows_to_list (chooser, list, INPUT_SOURCE_TYPE_XKB, id);
+       g_list_free (list);
 
-  return;
-}
+        gtk_widget_show_all (priv->input_list);
 
-static gint
-list_sort (GtkWidget *a,
-           GtkWidget *b,
-           gpointer   data)
-{
-  GtkWidget *chooser = data;
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  LocaleInfo *ia;
-  LocaleInfo *ib;
-  const gchar *la;
-  const gchar *lb;
-  gint retval;
-
-  /* Always goes at the start */
-  if (a == priv->no_results)
-    return -1;
-  if (b == priv->no_results)
-    return 1;
-
-  /* Always goes at the end */
-  if (a == priv->more_item)
-    return 1;
-  if (b == priv->more_item)
-    return -1;
-
-  ia = g_object_get_data (G_OBJECT (a), "locale-info");
-  ib = g_object_get_data (G_OBJECT (b), "locale-info");
-
-  /* The "Other" locale always goes at the end */
-  if (!ia->id[0] && ib->id[0])
-    return 1;
-  else if (ia->id[0] && !ib->id[0])
-    return -1;
-
-  retval = g_strcmp0 (ia->name, ib->name);
-  if (retval)
-    return retval;
-
-  la = g_object_get_data (G_OBJECT (a), "name");
-  lb = g_object_get_data (G_OBJECT (b), "name");
-
-  /* Only input sources have a "name" property and they should always
-     go after their respective heading */
-  if (la && !lb)
-    return 1;
-  else if (!la && lb)
-    return -1;
-  else if (!la && !lb)
-    return 0; /* Shouldn't happen */
-
-  /* The default input source always goes first in its group */
-  if (g_object_get_data (G_OBJECT (a), "default"))
-    return -1;
-  if (g_object_get_data (G_OBJECT (b), "default"))
-    return 1;
-
-  return g_strcmp0 (la, lb);
+out:
+       g_free (lang);
+       g_free (country);
 }
 
 static gboolean
-match_all (gchar       **words,
-           const gchar  *str)
+input_visible (GtkListBoxRow *row,
+                  gpointer       user_data)
 {
-  gchar **w;
+        CcInputChooser *chooser = user_data;
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        InputWidget *widget;
+        gboolean visible;
+        GtkWidget *child;
+        const char *search_term;
 
-  for (w = words; *w; ++w)
-    if (!strstr (str, *w))
-      return FALSE;
-
-  return TRUE;
-}
+        child = gtk_bin_get_child (GTK_BIN (row));
+        if (child == priv->more_item)
+                return !priv->showing_extra && g_hash_table_size (priv->inputs) > MIN_ROWS;
 
-static gboolean
-list_filter (GtkWidget *child,
-             gpointer   user_data)
-{
-  GtkDialog *chooser = user_data;
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  LocaleInfo *info;
-  gboolean is_extra;
-  const gchar *source_name;
+        widget = get_input_widget (child);
 
-  if (child == priv->more_item)
-    return !priv->showing_extra;
+        if (!priv->showing_extra && widget->is_extra)
+                return FALSE;
 
-  /* We hide this in the after-refilter handler below. */
-  if (child == priv->no_results)
-    return TRUE;
+        search_term = gtk_entry_get_text (GTK_ENTRY (priv->filter_entry));
+        if (!search_term || !*search_term)
+                return TRUE;
 
-  is_extra = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), "is-extra"));
+        visible = g_str_match_string (search_term, widget->name, TRUE);
+        return visible;
+}
 
-  if (!priv->showing_extra && is_extra)
-    return FALSE;
+static gint
+sort_inputs (GtkListBoxRow *a,
+                GtkListBoxRow *b,
+                gpointer       data)
+{
+        InputWidget *la, *lb;
 
-  if (!priv->filter_words)
-    return TRUE;
+        la = get_input_widget (gtk_bin_get_child (GTK_BIN (a)));
+        lb = get_input_widget (gtk_bin_get_child (GTK_BIN (b)));
 
-  info = g_object_get_data (G_OBJECT (child), "locale-info");
+        if (la == NULL)
+                return 1;
 
-  if (match_all (priv->filter_words, info->unaccented_name))
-    return TRUE;
+        if (lb == NULL)
+                return -1;
 
-  if (match_all (priv->filter_words, info->untranslated_name))
-    return TRUE;
+        if (la->is_extra && !lb->is_extra)
+                return 1;
 
-  source_name = g_object_get_data (G_OBJECT (child), "unaccented-name");
-  if (source_name && match_all (priv->filter_words, source_name))
-    return TRUE;
+        if (!la->is_extra && lb->is_extra)
+                return -1;
 
-  return FALSE;
+        return strcmp (la->name, lb->name);
 }
 
 static void
-update_separator_filter (GtkWidget **separator,
-                         GtkWidget  *child,
-                         GtkWidget  *before,
-                         gpointer    user_data)
+filter_changed (GtkEntry        *entry,
+                CcInputChooser *chooser)
 {
-  LocaleInfo *child_info = NULL;
-  LocaleInfo *before_info = NULL;
-
-  if (child)
-    child_info = g_object_get_data (G_OBJECT (child), "locale-info");
-
-  if (before)
-    before_info = g_object_get_data (G_OBJECT (before), "locale-info");
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->input_list));
+}
 
-  if (!child_info || !before_info)
-    return;
+static void
+show_more (CcInputChooser *chooser)
+{
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
 
-  if (child_info == before_info)
-    {
-      /* Create a regular separator if we don't have one */
-      if (*separator && !GTK_IS_SEPARATOR (*separator))
-        {
-          gtk_widget_destroy (*separator);
-          *separator = NULL;
-        }
+       if (g_hash_table_size (priv->inputs) <= MIN_ROWS)
+               return;
 
-      if (*separator == NULL)
-        *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-    }
-  else
-    {
-      /* Create a locale heading separator if we don't have one */
-      if (*separator && GTK_IS_SEPARATOR (*separator))
-        {
-          gtk_widget_destroy (*separator);
-          *separator = NULL;
-        }
+        gtk_widget_show (priv->filter_entry);
+        gtk_widget_grab_focus (priv->filter_entry);
 
-      if (*separator == NULL)
-        *separator = locale_separator_widget_new (child_info->name);
-    }
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
+                                       GTK_POLICY_NEVER,
+                                       GTK_POLICY_AUTOMATIC);
+       gtk_widget_set_valign (GTK_WIDGET (chooser), GTK_ALIGN_FILL);
 
-  g_object_ref_sink (*separator);
-  gtk_widget_show_all (*separator);
+        priv->showing_extra = TRUE;
+        gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->input_list));
+        g_object_notify_by_pspec (G_OBJECT (chooser), obj_props[PROP_SHOWING_EXTRA]);
 }
 
 static void
-show_filter_widgets (GtkWidget *chooser)
+set_input (CcInputChooser *chooser,
+           const gchar    *id,
+          const gchar    *type)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  LocaleInfo *info;
-  GHashTableIter iter;
-
-  remove_all_children (GTK_CONTAINER (priv->list));
-
-  gtk_container_add (GTK_CONTAINER (priv->list), priv->no_results);
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
 
-  g_hash_table_iter_init (&iter, priv->locales);
-  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
-    add_input_source_widgets_for_locale (chooser, info);
+        if (g_strcmp0 (priv->id, id) == 0 &&
+            g_strcmp0 (priv->type, type) == 0)
+                return;
 
-  gtk_widget_show_all (priv->list);
+        g_free (priv->id);
+       g_free (priv->type);
+        priv->id = g_strdup (id);
+       priv->type = g_strdup (type);
 
-  gtk_adjustment_set_value (priv->adjustment,
-                            gtk_adjustment_get_lower (priv->adjustment));
-  egg_list_box_set_separator_funcs (EGG_LIST_BOX (priv->list),
-                                    update_separator_filter, NULL, NULL);
-  egg_list_box_refilter (EGG_LIST_BOX (priv->list));
-  egg_list_box_set_selection_mode (EGG_LIST_BOX (priv->list), GTK_SELECTION_SINGLE);
+        sync_all_checkmarks (chooser);
 
-  if (gtk_widget_is_visible (priv->filter_entry))
-    gtk_widget_grab_focus (priv->filter_entry);
+       g_signal_emit (chooser, signals[CHANGED], 0);
 }
 
 static gboolean
-strvs_differ (gchar **av,
-              gchar **bv)
+confirm_choice (gpointer data)
 {
-  gchar **a, **b;
+        GtkWidget *widget = data;
 
-  for (a = av, b = bv; *a && *b; ++a, ++b)
-    if (!g_str_equal (*a, *b))
-      return TRUE;
+        g_signal_emit (widget, signals[CONFIRM], 0);
 
-  if (*a == NULL && *b == NULL)
-    return FALSE;
+        return G_SOURCE_REMOVE;
+}
 
-  return TRUE;
+static void
+row_activated (GtkListBox        *box,
+               GtkListBoxRow     *row,
+               CcInputChooser *chooser)
+{
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        GtkWidget *child;
+        InputWidget *widget;
+
+        if (row == NULL)
+                return;
+
+        child = gtk_bin_get_child (GTK_BIN (row));
+        if (child == priv->more_item) {
+                show_more (chooser);
+        } else {
+                widget = get_input_widget (child);
+                if (widget == NULL)
+                        return;
+                if (g_strcmp0 (priv->id, widget->id) == 0 &&
+                    g_strcmp0 (priv->type, widget->type) == 0)
+                        confirm_choice (chooser);
+                else
+                        set_input (chooser, widget->id, widget->type);
+        }
 }
 
 static void
-filter_changed (GtkWidget *chooser)
+update_header_func (GtkListBoxRow *child,
+                    GtkListBoxRow *before,
+                    gpointer       user_data)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  gboolean was_filtering;
-  gchar **previous_words;
-  gchar *filter_contents = NULL;
-
-  previous_words = priv->filter_words;
-  was_filtering = previous_words != NULL;
-
-  filter_contents =
-    cc_util_normalize_casefold_and_unaccent (gtk_entry_get_text (GTK_ENTRY (priv->filter_entry)));
-
-  if (filter_contents)
-    {
-      priv->filter_words = g_strsplit_set (g_strstrip (filter_contents), " ", 0);
-      g_free (filter_contents);
-    }
-
-  if (!priv->filter_words || !priv->filter_words[0])
-    {
-      g_clear_pointer (&priv->filter_words, g_strfreev);
-      if (was_filtering)
-        show_locale_widgets (chooser);
-    }
-  else
-    {
-      if (!was_filtering)
-        show_filter_widgets (chooser);
-      else if (strvs_differ (priv->filter_words, previous_words))
-        egg_list_box_refilter (EGG_LIST_BOX (priv->list));
-    }
-
-  g_strfreev (previous_words);
-}
+        GtkWidget *header;
 
-typedef struct {
-  gint count;
-  GtkWidget *ignore;
-} CountChildrenData;
+        if (before == NULL)
+                return;
+
+        header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+        gtk_list_box_row_set_header (child, header);
+        gtk_widget_show (header);
+}
 
+#ifdef HAVE_IBUS
 static void
-count_visible_children (GtkWidget *widget,
-                        gpointer   user_data)
-{
-  CountChildrenData *data = user_data;
-  if (widget != data->ignore &&
-      gtk_widget_get_child_visible (widget) &&
-      gtk_widget_get_visible (widget))
-    data->count++;
+update_ibus_active_sources (CcInputChooser *chooser)
+{
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        GList *rows, *l;
+        InputWidget *row;
+        const gchar *type;
+        const gchar *id;
+        IBusEngineDesc *engine_desc;
+        gchar *name;
+
+        rows = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
+        for (l = rows; l; l = l->next) {
+               row = get_input_widget (gtk_bin_get_child (GTK_BIN (l->data)));
+               if (row == NULL)
+                       continue;
+
+                type = row->type;
+                id = row->id;
+                if (g_strcmp0 (type, INPUT_SOURCE_TYPE_IBUS) != 0)
+                        continue;
+
+                engine_desc = g_hash_table_lookup (priv->ibus_engines, id);
+                if (engine_desc) {
+                        name = engine_get_display_name (engine_desc);
+                        gtk_label_set_text (GTK_LABEL (row->label), name);
+                        g_free (name);
+                }
+        }
+        g_list_free (rows);
 }
 
 static void
-end_refilter (EggListBox *list_box,
-              gpointer    user_data)
+get_ibus_locale_infos (CcInputChooser *chooser)
 {
-  GtkDialog *chooser = user_data;
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  CountChildrenData data = { 0 };
-  gboolean visible;
-
-  data.ignore = priv->no_results;
-
-  gtk_container_foreach (GTK_CONTAINER (list_box),
-                         count_visible_children, &data);
+       CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+       GHashTableIter iter;
+       const gchar *engine_id;
+       IBusEngineDesc *engine;
 
-  visible = (data.count == 0);
+       if (!priv->ibus_engines)
+               return;
 
-  gtk_widget_set_visible (priv->no_results, visible);
-  egg_list_box_set_selection_mode (EGG_LIST_BOX (priv->list),
-                                   visible ? GTK_SELECTION_NONE : GTK_SELECTION_SINGLE);
+       g_hash_table_iter_init (&iter, priv->ibus_engines);
+       while (g_hash_table_iter_next (&iter, (gpointer *) &engine_id, (gpointer *) &engine))
+                add_row_to_list (chooser, INPUT_SOURCE_TYPE_IBUS, engine_id);
 }
 
 static void
-show_more (GtkWidget *chooser)
-{
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
+fetch_ibus_engines_result (GObject       *object,
+                           GAsyncResult  *result,
+                           CcInputChooser *chooser)
+{
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        GList *list, *l;
+        GError *error;
+
+        error = NULL;
+        list = ibus_bus_list_engines_async_finish (priv->ibus, result, &error);
+        g_clear_object (&priv->ibus_cancellable);
+        if (!list && error) {
+                g_warning ("Couldn't finish IBus request: %s", error->message);
+                g_error_free (error);
+                return;
+        }
 
-  set_fixed_size (chooser);
+        /* Maps engine ids to engine description objects */
+        priv->ibus_engines = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
 
-  gtk_widget_show (priv->filter_entry);
-  gtk_widget_grab_focus (priv->filter_entry);
+        for (l = list; l; l = l->next) {
+                IBusEngineDesc *engine = l->data;
+                const gchar *engine_id;
 
-  priv->showing_extra = TRUE;
+               engine_id = ibus_engine_desc_get_name (engine);
+                if (g_str_has_prefix (engine_id, "xkb:"))
+                        g_object_unref (engine);
+                else
+                       g_hash_table_replace (priv->ibus_engines, (gpointer)engine_id, engine);
+       }
+       g_list_free (list);
 
-  egg_list_box_refilter (EGG_LIST_BOX (priv->list));
-}
+       update_ibus_active_sources (chooser);
+       get_ibus_locale_infos (chooser);
 
-static void
-child_activated (EggListBox *box,
-                 GtkWidget  *child,
-                 GtkWidget  *chooser)
-{
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  gpointer data;
-
-  if (!child)
-    return;
-
-  if (child == priv->more_item)
-    {
-      show_more (chooser);
-      return;
-    }
-
-  data = g_object_get_data (G_OBJECT (child), "back");
-  if (data)
-    {
-      show_locale_widgets (chooser);
-      return;
-    }
-
-  data = g_object_get_data (G_OBJECT (child), "name");
-  if (data)
-    {
-      /* It's an input source, we just want to select it */
-      return;
-    }
-
-  data = g_object_get_data (G_OBJECT (child), "locale-info");
-  if (data)
-    {
-      show_input_sources_for_locale (chooser, (LocaleInfo *) data);
-      return;
-    }
+        sync_all_checkmarks (chooser);
 }
 
 static void
-child_selected (EggListBox *box,
-                GtkWidget  *child,
-                GtkWidget  *chooser)
+fetch_ibus_engines (CcInputChooser *chooser)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
 
-  gtk_widget_set_sensitive (priv->add_button, child != NULL);
-}
+        priv->ibus_cancellable = g_cancellable_new ();
 
-static void
-add_default_widget (GtkWidget   *chooser,
-                    LocaleInfo  *info,
-                    const gchar *type,
-                    const gchar *id)
-{
-  info->default_input_source_widget = input_source_widget_new (chooser, type, id);
-  if (info->default_input_source_widget)
-    {
-      g_object_ref_sink (info->default_input_source_widget);
-      g_object_set_data (G_OBJECT (info->default_input_source_widget), "default", GINT_TO_POINTER (TRUE));
-      g_object_set_data (G_OBJECT (info->default_input_source_widget), "locale-info", info);
-    }
-}
+        ibus_bus_list_engines_async (priv->ibus,
+                                     -1,
+                                     priv->ibus_cancellable,
+                                     (GAsyncReadyCallback)fetch_ibus_engines_result,
+                                     chooser);
 
-static void
-add_widgets_to_table (GtkWidget   *chooser,
-                      LocaleInfo  *info,
-                      GList       *list,
-                      const gchar *type,
-                      const gchar *default_id)
-{
-  GHashTable *table;
-  GtkWidget *widget;
-  const gchar *id;
-
-  if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB))
-    table = info->layout_widgets_by_id;
-  else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS))
-    table = info->engine_widgets_by_id;
-  else
-    return;
-
-  while (list)
-    {
-      id = (const gchar *) list->data;
-
-      /* The widget for the default input source lives elsewhere */
-      if (g_strcmp0 (id, default_id))
-        {
-          widget = input_source_widget_new (chooser, type, id);
-          if (widget)
-            {
-              g_object_set_data (G_OBJECT (widget), "locale-info", info);
-              g_hash_table_replace (table, (gpointer) id, g_object_ref_sink (widget));
-            }
-        }
-      list = list->next;
-    }
+       /* We've got everything we needed, don't want to be called again. */
+       g_signal_handlers_disconnect_by_func (priv->ibus, fetch_ibus_engines, chooser);
 }
 
 static void
-add_widget (GtkWidget   *chooser,
-            LocaleInfo  *info,
-            const gchar *type,
-            const gchar *id)
-{
-  GList tmp = { 0 };
-  tmp.data = (gpointer) id;
-  add_widgets_to_table (chooser, info, &tmp, type, NULL);
-}
+maybe_start_ibus (void)
+{
+        /* IBus doesn't export API in the session bus. The only thing
+        * we have there is a well known name which we can use as a
+        * sure-fire way to activate it.
+        */
+        g_bus_unwatch_name (g_bus_watch_name (G_BUS_TYPE_SESSION,
+                                              IBUS_SERVICE_IBUS,
+                                              G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              NULL));
+}
+#endif
 
 static void
-add_widget_other (GtkWidget   *chooser,
-                  const gchar *type,
-                  const gchar *id)
+cc_input_chooser_constructed (GObject *object)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  LocaleInfo *info = g_hash_table_lookup (priv->locales, "");
-  add_widget (chooser, info, type, id);
-}
+        CcInputChooser *chooser = CC_INPUT_CHOOSER (object);
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+
+        G_OBJECT_CLASS (cc_input_chooser_parent_class)->constructed (object);
+
+       priv->xkb_info = gnome_xkb_info_new ();
 
 #ifdef HAVE_IBUS
-static gboolean
-maybe_set_as_default (GtkWidget   *chooser,
-                      LocaleInfo  *info,
-                      const gchar *engine_id)
-{
-  const gchar *type, *id;
+        ibus_init ();
+        if (!priv->ibus) {
+                priv->ibus = ibus_bus_new_async ();
+                if (ibus_bus_is_connected (priv->ibus))
+                        fetch_ibus_engines (chooser);
+                else
+                        g_signal_connect_swapped (priv->ibus, "connected",
+                                                  G_CALLBACK (fetch_ibus_engines), chooser);
+        }
+        maybe_start_ibus ();
+#endif
+
+       priv->inputs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+        priv->more_item = more_widget_new ();
+        priv->no_results = no_results_widget_new ();
+
+        gtk_list_box_set_sort_func (GTK_LIST_BOX (priv->input_list),
+                                    sort_inputs, chooser, NULL);
+        gtk_list_box_set_filter_func (GTK_LIST_BOX (priv->input_list),
+                                      input_visible, chooser, NULL);
+        gtk_list_box_set_header_func (GTK_LIST_BOX (priv->input_list),
+                                      update_header_func, chooser, NULL);
+        gtk_list_box_set_selection_mode (GTK_LIST_BOX (priv->input_list),
+                                         GTK_SELECTION_NONE);
+
+       if (priv->locale == NULL) {
+               priv->locale = cc_common_language_get_current_language ();
+       }
+
+        get_locale_infos (chooser);
+#ifdef HAVE_IBUS
+       get_ibus_locale_infos (chooser);
+#endif
 
-  if (!gnome_get_input_source_from_locale (info->id, &type, &id))
-    return FALSE;
+        gtk_container_add (GTK_CONTAINER (priv->input_list), priv->more_item);
+        gtk_list_box_set_placeholder (GTK_LIST_BOX (priv->input_list), priv->no_results);
 
-  if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS) &&
-      g_str_equal (id, engine_id) &&
-      info->default_input_source_widget == NULL)
-    {
-      add_default_widget (chooser, info, type, id);
-      return TRUE;
-    }
+        g_signal_connect (priv->filter_entry, "changed",
+                          G_CALLBACK (filter_changed),
+                          chooser);
 
-  return FALSE;
+        g_signal_connect (priv->input_list, "row-activated",
+                          G_CALLBACK (row_activated), chooser);
+
+        sync_all_checkmarks (chooser);
 }
 
 static void
-get_ibus_locale_infos (GtkWidget *chooser)
+cc_input_chooser_finalize (GObject *object)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  GHashTableIter iter;
-  LocaleInfo *info;
-  const gchar *engine_id;
-  IBusEngineDesc *engine;
-
-  if (!priv->ibus_engines)
-    return;
-
-  g_hash_table_iter_init (&iter, priv->ibus_engines);
-  while (g_hash_table_iter_next (&iter, (gpointer *) &engine_id, (gpointer *) &engine))
-    {
-      gchar *lang_code = NULL;
-      gchar *country_code = NULL;
-      const gchar *ibus_locale = ibus_engine_desc_get_language (engine);
-
-      if (gnome_parse_locale (ibus_locale, &lang_code, &country_code, NULL, NULL) &&
-          lang_code != NULL &&
-          country_code != NULL)
-        {
-          gchar *locale = g_strdup_printf ("%s_%s.utf8", lang_code, country_code);
-
-          info = g_hash_table_lookup (priv->locales, locale);
-          if (info)
-            {
-              const gchar *type, *id;
-
-              if (gnome_get_input_source_from_locale (locale, &type, &id) &&
-                  g_str_equal (type, INPUT_SOURCE_TYPE_IBUS) &&
-                  g_str_equal (id, engine_id))
-                {
-                  add_default_widget (chooser, info, type, id);
-                }
-              else
-                {
-                  add_widget (chooser, info, INPUT_SOURCE_TYPE_IBUS, engine_id);
-                }
-            }
-          else
-            {
-              add_widget_other (chooser, INPUT_SOURCE_TYPE_IBUS, engine_id);
-            }
+       CcInputChooser *chooser = CC_INPUT_CHOOSER (object);
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
 
-          g_free (locale);
-        }
-      else if (lang_code != NULL)
-        {
-          GHashTableIter iter;
-          GHashTable *locales_for_language;
-          gchar *language;
-
-          /* Most IBus engines only specify the language so we try to
-             add them to all locales for that language. */
-
-          language = gnome_get_language_from_code (lang_code, NULL);
-          if (language)
-            locales_for_language = g_hash_table_lookup (priv->locales_by_language, language);
-          else
-            locales_for_language = NULL;
-          g_free (language);
-
-          if (locales_for_language)
-            {
-              g_hash_table_iter_init (&iter, locales_for_language);
-              while (g_hash_table_iter_next (&iter, (gpointer *) &info, NULL))
-                if (!maybe_set_as_default (chooser, info, engine_id))
-                  add_widget (chooser, info, INPUT_SOURCE_TYPE_IBUS, engine_id);
-            }
-          else
-            {
-              add_widget_other (chooser, INPUT_SOURCE_TYPE_IBUS, engine_id);
-            }
-        }
-      else
-        {
-          add_widget_other (chooser, INPUT_SOURCE_TYPE_IBUS, engine_id);
-        }
+       g_clear_object (&priv->xkb_info);
+       g_hash_table_unref (priv->inputs);
+#ifdef HAVE_IBUS
+        g_clear_object (&priv->ibus);
+        if (priv->ibus_cancellable)
+                g_cancellable_cancel (priv->ibus_cancellable);
+        g_clear_object (&priv->ibus_cancellable);
+        g_clear_pointer (&priv->ibus_engines, g_hash_table_destroy);
+#endif
+
+       G_OBJECT_CLASS (cc_input_chooser_parent_class)->finalize (object);
+}
 
-      g_free (country_code);
-      g_free (lang_code);
-    }
+static void
+cc_input_chooser_get_property (GObject      *object,
+                                  guint         prop_id,
+                                  GValue       *value,
+                                  GParamSpec   *pspec)
+{
+        CcInputChooser *chooser = CC_INPUT_CHOOSER (object);
+        switch (prop_id) {
+        case PROP_SHOWING_EXTRA:
+                g_value_set_boolean (value, cc_input_chooser_get_showing_extra (chooser));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
 }
-#endif  /* HAVE_IBUS */
 
 static void
-add_locale_to_table (GHashTable  *table,
-                     const gchar *lang_code,
-                     LocaleInfo  *info)
+cc_input_chooser_class_init (CcInputChooserClass *klass)
 {
-  GHashTable *set;
-  gchar *language;
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), 
"/org/gnome/initial-setup/input-chooser.ui");
+
+        gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), CcInputChooser, 
filter_entry);
+        gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), CcInputChooser, input_list);
+        gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), CcInputChooser, 
scrolled_window);
+
+       object_class->finalize = cc_input_chooser_finalize;
+        object_class->get_property = cc_input_chooser_get_property;
+        object_class->constructed = cc_input_chooser_constructed;
+
+        obj_props[PROP_SHOWING_EXTRA] =
+                g_param_spec_string ("showing-extra", "", "", "",
+                                     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
-  language = gnome_get_language_from_code (lang_code, NULL);
+       signals[CHANGED] = 
+               g_signal_new ("changed",
+                             G_TYPE_FROM_CLASS (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             0,
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
 
-  set = g_hash_table_lookup (table, language);
-  if (!set)
-    {
-      set = g_hash_table_new (NULL, NULL);
-      g_hash_table_replace (table, g_strdup (language), set);
-    }
-  g_hash_table_add (set, info);
+        signals[CONFIRM] =
+                g_signal_new ("confirm",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              0,
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
 
-  g_free (language);
+        g_object_class_install_properties (object_class, PROP_LAST, obj_props);
 }
 
 static void
-add_ids_to_set (GHashTable *set,
-                GList      *list)
+cc_input_chooser_init (CcInputChooser *chooser)
 {
-  while (list)
-    {
-      g_hash_table_add (set, list->data);
-      list = list->next;
-    }
+        gtk_widget_init_template (GTK_WIDGET (chooser));
 }
 
-static void
-get_locale_infos (GtkWidget *chooser)
+void
+cc_input_chooser_clear_filter (CcInputChooser *chooser)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  GHashTable *layouts_with_locale;
-  LocaleInfo *info;
-  gchar **locale_ids;
-  gchar **locale;
-  GList *list, *l;
-
-  priv->locales = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                         NULL, locale_info_free);
-  priv->locales_by_language = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                     g_free, (GDestroyNotify) g_hash_table_destroy);
-
-  layouts_with_locale = g_hash_table_new (g_str_hash, g_str_equal);
-
-  locale_ids = gnome_get_all_locales ();
-  for (locale = locale_ids; *locale; ++locale)
-    {
-      gchar *lang_code, *country_code;
-      gchar *simple_locale;
-      gchar *untranslated_locale;
-      const gchar *type = NULL;
-      const gchar *id = NULL;
-
-      if (!gnome_parse_locale (*locale, &lang_code, &country_code, NULL, NULL))
-        continue;
-
-      simple_locale = g_strdup_printf ("%s_%s.utf8", lang_code, country_code);
-      if (g_hash_table_contains (priv->locales, simple_locale))
-        goto free_and_continue;
-
-      /* We are not interested in locales whose name we can't display */
-      untranslated_locale = gnome_get_language_from_locale (simple_locale, "C");
-      if (!untranslated_locale)
-        goto free_and_continue;
-
-      info = g_new0 (LocaleInfo, 1);
-      info->id = g_strdup (simple_locale);
-      info->name = gnome_get_language_from_locale (simple_locale, NULL);
-      info->unaccented_name = cc_util_normalize_casefold_and_unaccent (info->name);
-      info->untranslated_name = cc_util_normalize_casefold_and_unaccent (untranslated_locale);
-      g_free (untranslated_locale);
-
-      g_hash_table_replace (priv->locales, simple_locale, info);
-      add_locale_to_table (priv->locales_by_language, lang_code, info);
-
-      if (gnome_get_input_source_from_locale (simple_locale, &type, &id) &&
-          g_str_equal (type, INPUT_SOURCE_TYPE_XKB))
-        {
-          add_default_widget (chooser, info, type, id);
-          g_hash_table_add (layouts_with_locale, (gpointer) id);
-        }
-
-      /* We don't own these ids */
-      info->layout_widgets_by_id = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                          NULL, g_object_unref);
-      info->engine_widgets_by_id = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                          NULL, g_object_unref);
-
-      list = gnome_xkb_info_get_layouts_for_language (priv->xkb_info, lang_code);
-      add_widgets_to_table (chooser, info, list, INPUT_SOURCE_TYPE_XKB, id);
-      add_ids_to_set (layouts_with_locale, list);
-      g_list_free (list);
-
-      list = gnome_xkb_info_get_layouts_for_country (priv->xkb_info, country_code);
-      add_widgets_to_table (chooser, info, list, INPUT_SOURCE_TYPE_XKB, id);
-      add_ids_to_set (layouts_with_locale, list);
-      g_list_free (list);
-
-    free_and_continue:
-      g_free (lang_code);
-      g_free (country_code);
-      g_free (simple_locale);
-    }
-  g_strfreev (locale_ids);
-
-  /* Add a "Other" locale to hold the remaining input sources */
-  info = g_new0 (LocaleInfo, 1);
-  info->id = g_strdup ("");
-  info->name = g_strdup (_("Other"));
-  info->unaccented_name = g_strdup ("");
-  info->untranslated_name = g_strdup ("");
-  g_hash_table_replace (priv->locales, info->id, info);
-
-  info->layout_widgets_by_id = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                      NULL, g_object_unref);
-  info->engine_widgets_by_id = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                      NULL, g_object_unref);
-
-  list = gnome_xkb_info_get_all_layouts (priv->xkb_info);
-  for (l = list; l; l = l->next)
-    if (!g_hash_table_contains (layouts_with_locale, l->data))
-      add_widget_other (chooser, INPUT_SOURCE_TYPE_XKB, l->data);
-
-  g_list_free (list);
-
-  g_hash_table_destroy (layouts_with_locale);
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        gtk_entry_set_text (GTK_ENTRY (priv->filter_entry), "");
 }
 
-static void
-cc_input_chooser_private_free (gpointer data)
+const gchar *
+cc_input_chooser_get_input_id (CcInputChooser *chooser)
 {
-  CcInputChooserPrivate *priv = data;
-
-  g_object_unref (priv->more_item);
-  g_object_unref (priv->no_results);
-  g_hash_table_destroy (priv->locales);
-  g_hash_table_destroy (priv->locales_by_language);
-  g_strfreev (priv->filter_words);
-  g_free (priv);
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        return priv->id;
 }
 
-GtkWidget *
-cc_input_chooser_new (GtkWindow    *main_window,
-                      GnomeXkbInfo *xkb_info,
-                      GHashTable   *ibus_engines)
+const gchar *
+cc_input_chooser_get_input_type (CcInputChooser *chooser)
 {
-  GtkBuilder *builder;
-  GtkWidget *chooser;
-  CcInputChooserPrivate *priv;
-  gint width;
-  GError *error = NULL;
-
-  builder = gtk_builder_new ();
-  if (gtk_builder_add_from_resource (builder, "/org/gnome/initial-setup/input-chooser.ui", &error) == 0)
-    {
-      g_object_unref (builder);
-      g_warning ("failed to load input chooser: %s", error->message);
-      g_error_free (error);
-      return NULL;
-    }
-  chooser = WID ("input-dialog");
-  priv = g_new0 (CcInputChooserPrivate, 1);
-  g_object_set_data_full (G_OBJECT (chooser), "private", priv, cc_input_chooser_private_free);
-  g_object_set_data_full (G_OBJECT (chooser), "builder", builder, g_object_unref);
-
-  priv->xkb_info = xkb_info;
-  priv->ibus_engines = ibus_engines;
-
-  priv->add_button = WID ("add-button");
-  priv->filter_entry = WID ("filter-entry");
-  priv->list = WID ("list");
-  priv->scrolledwindow = WID ("scrolledwindow");
-  priv->adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scrolledwindow));
-
-  priv->more_item = g_object_ref_sink (more_widget_new ());
-  priv->no_results = g_object_ref_sink (no_results_widget_new ());
-
-  egg_list_box_set_adjustment (EGG_LIST_BOX (priv->list), priv->adjustment);
-  egg_list_box_set_filter_func (EGG_LIST_BOX (priv->list), list_filter, chooser, NULL);
-  egg_list_box_set_sort_func (EGG_LIST_BOX (priv->list), list_sort, chooser, NULL);
-  g_signal_connect (priv->list, "child-activated", G_CALLBACK (child_activated), chooser);
-  g_signal_connect (priv->list, "child-selected", G_CALLBACK (child_selected), chooser);
-  g_signal_connect_after (priv->list, "refilter", G_CALLBACK (end_refilter), chooser);
-
-  g_signal_connect_swapped (priv->filter_entry, "changed", G_CALLBACK (filter_changed), chooser);
-
-  get_locale_infos (chooser);
-#ifdef HAVE_IBUS
-  get_ibus_locale_infos (chooser);
-#endif  /* HAVE_IBUS */
-  show_locale_widgets (chooser);
-
-  /* Try to come up with a sensible width */
-  gtk_window_get_size (main_window, &width, NULL);
-  gtk_widget_set_size_request (chooser, width * MAIN_WINDOW_WIDTH_RATIO, -1);
-  gtk_window_set_resizable (GTK_WINDOW (chooser), TRUE);
-
-  gtk_window_set_transient_for (GTK_WINDOW (chooser), main_window);
-
-  return chooser;
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        return priv->type;
 }
 
 void
-cc_input_chooser_set_ibus_engines (GtkWidget  *chooser,
-                                   GHashTable *ibus_engines)
+cc_input_chooser_get_layout (CcInputChooser *chooser,
+                            const gchar    **layout,
+                            const gchar    **variant)
 {
-#ifdef HAVE_IBUS
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
 
-  /* This should only be called once when IBus shows up in case it
-     wasn't up yet when the user opened the input chooser dialog. */
-  g_return_if_fail (priv->ibus_engines == NULL);
+       get_layout (chooser, priv->type, priv->id, layout, variant);
+}
 
-  priv->ibus_engines = ibus_engines;
-  get_ibus_locale_infos (chooser);
-  show_locale_widgets (chooser);
-#endif  /* HAVE_IBUS */
+void
+cc_input_chooser_set_input (CcInputChooser *chooser,
+                            const gchar    *id,
+                           const gchar    *type)
+{
+        set_input (chooser, id, type);
 }
 
 gboolean
-cc_input_chooser_get_selected (GtkWidget  *chooser,
-                               gchar     **type,
-                               gchar     **id,
-                               gchar     **name)
+cc_input_chooser_get_showing_extra (CcInputChooser *chooser)
 {
-  CcInputChooserPrivate *priv = GET_PRIVATE (chooser);
-  GtkWidget *selected;
-  const gchar *t, *i, *n;
-
-  selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->list));
-  if (!selected)
-    return FALSE;
-
-  t = g_object_get_data (G_OBJECT (selected), "type");
-  i = g_object_get_data (G_OBJECT (selected), "id");
-  n = g_object_get_data (G_OBJECT (selected), "name");
-
-  if (!t || !i || !n)
-    return FALSE;
-
-  *type = g_strdup (t);
-  *id = g_strdup (i);
-  *name = g_strdup (n);
-
-  return TRUE;
+        CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser);
+        return priv->showing_extra;
 }
diff --git a/gnome-initial-setup/pages/keyboard/cc-input-chooser.h 
b/gnome-initial-setup/pages/keyboard/cc-input-chooser.h
index a9edc65..dfd6a28 100644
--- a/gnome-initial-setup/pages/keyboard/cc-input-chooser.h
+++ b/gnome-initial-setup/pages/keyboard/cc-input-chooser.h
@@ -12,31 +12,53 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ *     Jasper St. Pierre <jstpierre mecheye net>
+ *     Matthias Clasen <mclasen redhat com>
  */
 
 #ifndef __GIS_INPUT_CHOOSER_H__
 #define __GIS_INPUT_CHOOSER_H__
 
 #include <gtk/gtk.h>
+#include <glib-object.h>
 
-#define GNOME_DESKTOP_USE_UNSTABLE_API
-#include <libgnome-desktop/gnome-xkb-info.h>
-
+#define CC_TYPE_INPUT_CHOOSER            (cc_input_chooser_get_type ())
+#define CC_INPUT_CHOOSER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TYPE_INPUT_CHOOSER, 
CcInputChooser))
+#define CC_INPUT_CHOOSER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  CC_TYPE_INPUT_CHOOSER, 
CcInputChooserClass))
+#define CC_IS_INPUT_CHOOSER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TYPE_INPUT_CHOOSER))
+#define CC_IS_INPUT_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  CC_TYPE_INPUT_CHOOSER))
+#define CC_INPUT_CHOOSER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  CC_TYPE_INPUT_CHOOSER, 
CcInputChooserClass))
 
 G_BEGIN_DECLS
 
-GtkWidget   *cc_input_chooser_new          (GtkWindow    *parent,
-                                            GnomeXkbInfo *xkb_info,
-                                            GHashTable   *ibus_engines);
-void         cc_input_chooser_set_ibus_engines (GtkWidget *chooser,
-                                                GHashTable *ibus_engines);
-gboolean     cc_input_chooser_get_selected (GtkWidget    *chooser,
-                                            gchar       **type,
-                                            gchar       **id,
-                                            gchar       **name);
+typedef struct _CcInputChooser        CcInputChooser;
+typedef struct _CcInputChooserClass   CcInputChooserClass;
+
+struct _CcInputChooser
+{
+        GtkBox parent;
+};
+
+struct _CcInputChooserClass
+{
+        GtkBoxClass parent_class;
+};
+
+GType cc_input_chooser_get_type (void);
+
+void          cc_input_chooser_clear_filter (CcInputChooser *chooser);
+const gchar * cc_input_chooser_get_input_id (CcInputChooser  *chooser);
+const gchar * cc_input_chooser_get_input_type (CcInputChooser  *chooser);
+void          cc_input_chooser_set_input (CcInputChooser *chooser,
+                                          const gchar    *id,
+                                          const gchar    *type);
+void         cc_input_chooser_get_layout (CcInputChooser *chooser,
+                                          const gchar    **layout,
+                                          const gchar    **variant);
+gboolean      cc_input_chooser_get_showing_extra (CcInputChooser *chooser);
 
 G_END_DECLS
 
diff --git a/gnome-initial-setup/pages/keyboard/cc-util.c b/gnome-initial-setup/pages/keyboard/cc-util.c
new file mode 100644
index 0000000..e51a9d2
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-util.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+
+#include "cc-util.h"
+
+/* Combining diacritical mark?
+ *  Basic range: [0x0300,0x036F]
+ *  Supplement:  [0x1DC0,0x1DFF]
+ *  For Symbols: [0x20D0,0x20FF]
+ *  Half marks:  [0xFE20,0xFE2F]
+ */
+#define IS_CDM_UCS4(c) (((c) >= 0x0300 && (c) <= 0x036F)  || \
+                        ((c) >= 0x1DC0 && (c) <= 0x1DFF)  || \
+                        ((c) >= 0x20D0 && (c) <= 0x20FF)  || \
+                        ((c) >= 0xFE20 && (c) <= 0xFE2F))
+
+/* Copied from tracker/src/libtracker-fts/tracker-parser-glib.c under the GPL
+ * And then from gnome-shell/src/shell-util.c
+ *
+ * Originally written by Aleksander Morgado <aleksander gnu org>
+ */
+char *
+cc_util_normalize_casefold_and_unaccent (const char *str)
+{
+  char *normalized, *tmp;
+  int i = 0, j = 0, ilen;
+
+  if (str == NULL)
+    return NULL;
+
+  normalized = g_utf8_normalize (str, -1, G_NORMALIZE_NFKD);
+  tmp = g_utf8_casefold (normalized, -1);
+  g_free (normalized);
+
+  ilen = strlen (tmp);
+
+  while (i < ilen)
+    {
+      gunichar unichar;
+      gchar *next_utf8;
+      gint utf8_len;
+
+      /* Get next character of the word as UCS4 */
+      unichar = g_utf8_get_char_validated (&tmp[i], -1);
+
+      /* Invalid UTF-8 character or end of original string. */
+      if (unichar == (gunichar) -1 ||
+          unichar == (gunichar) -2)
+        {
+          break;
+        }
+
+      /* Find next UTF-8 character */
+      next_utf8 = g_utf8_next_char (&tmp[i]);
+      utf8_len = next_utf8 - &tmp[i];
+
+      if (IS_CDM_UCS4 ((guint32) unichar))
+        {
+          /* If the given unichar is a combining diacritical mark,
+           * just update the original index, not the output one */
+          i += utf8_len;
+          continue;
+        }
+
+      /* If already found a previous combining
+       * diacritical mark, indexes are different so
+       * need to copy characters. As output and input
+       * buffers may overlap, need to use memmove
+       * instead of memcpy */
+      if (i != j)
+        {
+          memmove (&tmp[j], &tmp[i], utf8_len);
+        }
+
+      /* Update both indexes */
+      i += utf8_len;
+      j += utf8_len;
+    }
+
+  /* Force proper string end */
+  tmp[j] = '\0';
+
+  return tmp;
+}
diff --git a/gnome-initial-setup/pages/keyboard/cc-util.h b/gnome-initial-setup/pages/keyboard/cc-util.h
new file mode 100644
index 0000000..42b09ff
--- /dev/null
+++ b/gnome-initial-setup/pages/keyboard/cc-util.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * The Control Center 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The Control Center 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 the Control Center; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+#ifndef _CC_UTIL_H
+#define _CC_UTIL_H
+
+#include <glib.h>
+
+char *cc_util_normalize_casefold_and_unaccent (const char *str);
+
+#endif
diff --git a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c 
b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c
index f95619e..aa497b3 100644
--- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c
+++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.c
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Sergey Udaltsov <svu gnome org>
  *         Michael Wood <michael g wood intel com>
@@ -28,1184 +27,222 @@
 #include <locale.h>
 #include <glib/gi18n.h>
 #include <gio/gio.h>
-#include <gio/gdesktopappinfo.h>
 #include <gtk/gtk.h>
 #include <polkit/polkit.h>
 
 #include "gis-keyboard-page.h"
 #include "keyboard-resources.h"
 #include "cc-input-chooser.h"
-#include "cc-keyboard-query.h"
-
-#define GNOME_DESKTOP_USE_UNSTABLE_API
-#include <libgnome-desktop/gnome-xkb-info.h>
-#include <libgnome-desktop/gnome-languages.h>
-
-#ifdef HAVE_IBUS
-#include <ibus.h>
-#include "cc-ibus-utils.h"
-#endif
-
-#include <act/act.h>
-#include <unistd.h>
-#include <egg-list-box.h>
 
 #define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources"
 #define KEY_CURRENT_INPUT_SOURCE "current"
 #define KEY_INPUT_SOURCES        "sources"
 
-#define INPUT_SOURCE_TYPE_XKB "xkb"
-#define INPUT_SOURCE_TYPE_IBUS "ibus"
-
-#define MAX_INPUT_ROWS_VISIBLE 5
-
 struct _GisKeyboardPagePrivate {
-        GDBusProxy  *localed;
-        GCancellable *cancellable;
-
-        GtkWidget *input_section;
-        GtkWidget *input_list;
-        GtkWidget *add_input;
-        GtkWidget *remove_input;
-        GtkWidget *show_config;
-        GtkWidget *show_layout;
-        GtkWidget *auto_detect;
-        GtkWidget *input_scrolledwindow;
-        GList *selected_input_sorted;
-        guint n_input_rows;
-        GPid gkbd_pid;
-        GPermission *permission;
-
+        GtkWidget *input_chooser;
 
+       GDBusProxy *localed;
+       GCancellable *cancellable;
+       GPermission *permission;
         GSettings *input_settings;
-        GnomeXkbInfo *xkb_info;
-#ifdef HAVE_IBUS
-        IBusBus *ibus;
-        GHashTable *ibus_engines;
-        GCancellable *ibus_cancellable;
-#endif
-
-        guint next_page_id;
 };
 typedef struct _GisKeyboardPagePrivate GisKeyboardPagePrivate;
 
-#define OBJ(type,name) ((type)gtk_builder_get_object(GIS_PAGE (self)->builder,(name)))
-#define WID(name) OBJ(GtkWidget*,name)
-
 G_DEFINE_TYPE_WITH_PRIVATE (GisKeyboardPage, gis_keyboard_page, GIS_TYPE_PAGE);
 
 static void
-gis_keyboard_page_dispose (GObject *gobject)
-{
-  GisKeyboardPage *page = GIS_KEYBOARD_PAGE (gobject);
-  GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (page);
-
-  if (priv->cancellable)
-    {
-      g_cancellable_cancel (priv->cancellable);
-      g_clear_object (&priv->cancellable);
-    }
-
-  if (priv->input_settings)
-    {
-      g_signal_handlers_disconnect_by_data (priv->input_settings, page);
-      g_clear_object (&priv->input_settings);
-    }
-
-  if (priv->next_page_id != 0)
-    {
-      g_signal_handler_disconnect (gis_driver_get_assistant (GIS_PAGE (page)->driver),
-                                   priv->next_page_id);
-      priv->next_page_id = 0;
-    }
-
-  g_clear_object (&priv->permission);
-  g_clear_object (&priv->localed);
-  g_clear_object (&priv->xkb_info);
-
-#ifdef HAVE_IBUS
-  g_clear_object (&priv->ibus);
-  if (priv->ibus_cancellable)
-    g_cancellable_cancel (priv->ibus_cancellable);
-  g_clear_object (&priv->ibus_cancellable);
-#endif
-
-  G_OBJECT_CLASS (gis_keyboard_page_parent_class)->dispose (gobject);
-}
-
-static void
 gis_keyboard_page_finalize (GObject *object)
 {
        GisKeyboardPage *self = GIS_KEYBOARD_PAGE (object);
         GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
 
-#ifdef HAVE_IBUS
-        g_clear_pointer (&priv->ibus_engines, g_hash_table_destroy);
-        g_clear_pointer (&priv->selected_input_sorted, g_list_free);
-#endif
-
-       G_OBJECT_CLASS (gis_keyboard_page_parent_class)->finalize (object);
-}
-
-static void localed_proxy_ready (GObject *source, GAsyncResult *res, gpointer data);
-static void setup_input_section (GisKeyboardPage *self);
-static void update_input (GisKeyboardPage *self);
-
-static void
-next_page_cb (GisAssistant *assistant,
-              GisPage      *which_page,
-              GisPage      *this_page)
-{
-        if (which_page == this_page)
-                update_input (GIS_KEYBOARD_PAGE (this_page));
-}
-
-static void
-gis_keyboard_page_constructed (GObject *object)
-{
-        GisKeyboardPage *self = GIS_KEYBOARD_PAGE (object);
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-
-        G_OBJECT_CLASS (gis_keyboard_page_parent_class)->constructed (object);
-
-        gtk_container_add (GTK_CONTAINER (self), WID ("keyboard_page"));
-
-        setup_input_section (self);
-
-        priv->cancellable = g_cancellable_new ();
-
-        g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
-                                  G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
-                                  NULL,
-                                  "org.freedesktop.locale1",
-                                  "/org/freedesktop/locale1",
-                                  "org.freedesktop.locale1",
-                                  priv->cancellable,
-                                  (GAsyncReadyCallback) localed_proxy_ready,
-                                  self);
-
-        /* If we're in new user mode then we're manipulating system settings */
-        if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER)
-                priv->permission = polkit_permission_new_sync ("org.freedesktop.locale1.set-keyboard", NULL, 
NULL, NULL);
-
-        priv->next_page_id = g_signal_connect (gis_driver_get_assistant (GIS_PAGE (self)->driver),
-                                               "next-page",
-                                               G_CALLBACK (next_page_cb),
-                                               self);
-
-        gis_page_set_complete (GIS_PAGE (self), TRUE);
-        gtk_widget_show (GTK_WIDGET (self));
-}
-
-static void
-gis_keyboard_page_locale_changed (GisPage *page)
-{
-        gis_page_set_title (GIS_PAGE (page), _("Keyboard Layouts"));
-}
-
-static void
-gis_keyboard_page_class_init (GisKeyboardPageClass * klass)
-{
-       GObjectClass *object_class = G_OBJECT_CLASS (klass);
-       GisPageClass * page_class = GIS_PAGE_CLASS (klass);
-
-        page_class->page_id = PAGE_ID;
-        page_class->locale_changed = gis_keyboard_page_locale_changed;
-
-        object_class->constructed = gis_keyboard_page_constructed;
-        object_class->dispose = gis_keyboard_page_dispose;
-        object_class->finalize = gis_keyboard_page_finalize;
-}
-
-static void
-update_separator_func (GtkWidget **separator,
-                       GtkWidget  *child,
-                       GtkWidget  *before,
-                       gpointer    user_data)
-{
-        if (before == NULL)
-                return;
-
-        if (*separator == NULL) {
-                *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-                g_object_ref_sink (*separator);
-                gtk_widget_show (*separator);
-        }
-}
-
-
-static void show_input_chooser (GisKeyboardPage *self);
-static void remove_selected_input (GisKeyboardPage *self);
-
-#ifdef HAVE_IBUS
-static void
-update_ibus_active_sources (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GList *rows, *l;
-        GtkWidget *row;
-        const gchar *type;
-        const gchar *id;
-        IBusEngineDesc *engine_desc;
-        gchar *display_name;
-        GtkWidget *label;
-
-        rows = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
-        for (l = rows; l; l = l->next) {
-                row = l->data;
-                type = g_object_get_data (G_OBJECT (row), "type");
-                id = g_object_get_data (G_OBJECT (row), "id");
-                if (g_strcmp0 (type, INPUT_SOURCE_TYPE_IBUS) != 0)
-                        continue;
-
-                engine_desc = g_hash_table_lookup (priv->ibus_engines, id);
-                if (engine_desc) {
-                        display_name = engine_get_display_name (engine_desc);
-                        label = GTK_WIDGET (g_object_get_data (G_OBJECT (row), "label"));
-                        gtk_label_set_text (GTK_LABEL (label), display_name);
-                        g_free (display_name);
-                }
-        }
-        g_list_free (rows);
-}
-
-static void
-update_input_chooser (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *chooser;
-
-        chooser = g_object_get_data (G_OBJECT (self), "input-chooser");
-        if (!chooser)
-                return;
-
-        cc_input_chooser_set_ibus_engines (chooser, priv->ibus_engines);
-}
-
-static void
-fetch_ibus_engines_result (GObject       *object,
-                           GAsyncResult  *result,
-                           GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GList *list, *l;
-        GError *error;
-
-        error = NULL;
-        list = ibus_bus_list_engines_async_finish (priv->ibus, result, &error);
-        g_clear_object (&priv->ibus_cancellable);
-        if (!list && error) {
-                g_warning ("Couldn't finish IBus request: %s", error->message);
-                g_error_free (error);
-                return;
-        }
-
-        /* Maps engine ids to engine description objects */
-        priv->ibus_engines = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
-
-        for (l = list; l; l = l->next) {
-                IBusEngineDesc *engine = l->data;
-                const gchar *engine_id = ibus_engine_desc_get_name (engine);
-
-                if (g_str_has_prefix (engine_id, "xkb:"))
-                        g_object_unref (engine);
-                else
-                        g_hash_table_replace (priv->ibus_engines, (gpointer)engine_id, engine);
-        }
-        g_list_free (list);
-
-        update_ibus_active_sources (self);
-        update_input_chooser (self);
-}
-
-static void
-fetch_ibus_engines (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-
-        priv->ibus_cancellable = g_cancellable_new ();
-
-        ibus_bus_list_engines_async (priv->ibus,
-                                     -1,
-                                     priv->ibus_cancellable,
-                                     (GAsyncReadyCallback)fetch_ibus_engines_result,
-                                     self);
-
-  /* We've got everything we needed, don't want to be called again. */
-  g_signal_handlers_disconnect_by_func (priv->ibus, fetch_ibus_engines, self);
-}
-
-static void
-maybe_start_ibus (void)
-{
-        /* IBus doesn't export API in the session bus. The only thing
-         * we have there is a well known name which we can use as a
-         * sure-fire way to activate it.
-         */
-        g_bus_unwatch_name (g_bus_watch_name (G_BUS_TYPE_SESSION,
-                                              IBUS_SERVICE_IBUS,
-                                              G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
-                                              NULL,
-                                              NULL,
-                                              NULL,
-                                              NULL));
-}
-
-static GDesktopAppInfo *
-setup_app_info_for_id (const gchar *id)
-{
-  GDesktopAppInfo *app_info;
-  gchar *desktop_file_name;
-  gchar **strv;
-
-  strv = g_strsplit (id, ":", 2);
-  desktop_file_name = g_strdup_printf ("ibus-setup-%s.desktop", strv[0]);
-  g_strfreev (strv);
-
-  app_info = g_desktop_app_info_new (desktop_file_name);
-  g_free (desktop_file_name);
-
-  return app_info;
-}
-#endif
-
-static void
-adjust_input_list_scrolling (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-
-        if (priv->n_input_rows >= MAX_INPUT_ROWS_VISIBLE) {
-                GtkWidget *parent;
-                gint height;
+       if (priv->cancellable)
+               g_cancellable_cancel (priv->cancellable);
+       g_clear_object (&priv->cancellable);
 
-                parent = gtk_widget_get_parent (priv->input_scrolledwindow);
-                gtk_widget_get_preferred_height (parent, NULL, &height);
-                gtk_widget_set_size_request (parent, -1, height);
+       g_clear_object (&priv->permission);
+       g_clear_object (&priv->localed);
+       g_clear_object (&priv->input_settings);
 
-                gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->input_scrolledwindow),
-                                                GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-        } else {
-                gtk_widget_set_size_request (gtk_widget_get_parent (priv->input_scrolledwindow), -1, -1);
-                gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->input_scrolledwindow),
-                                                GTK_POLICY_NEVER, GTK_POLICY_NEVER);
-        }
-}
-
-static GtkWidget *
-add_input_row (GisKeyboardPage   *self,
-               const gchar     *type,
-               const gchar     *id,
-               const gchar     *name,
-               GDesktopAppInfo *app_info)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *row;
-        GtkWidget *label;
-        GtkWidget *image;
-
-        row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-        label = gtk_label_new (name);
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-        gtk_widget_set_margin_left (label, 20);
-        gtk_widget_set_margin_right (label, 20);
-        gtk_widget_set_margin_top (label, 6);
-        gtk_widget_set_margin_bottom (label, 6);
-        gtk_box_pack_start (GTK_BOX (row), label, TRUE, TRUE, 0);
-
-        if (strcmp (type, INPUT_SOURCE_TYPE_IBUS) == 0) {
-                image = gtk_image_new_from_icon_name ("system-run-symbolic", GTK_ICON_SIZE_BUTTON);
-                gtk_widget_set_margin_left (image, 20);
-                gtk_widget_set_margin_right (image, 20);
-                gtk_widget_set_margin_top (image, 6);
-                gtk_widget_set_margin_bottom (image, 6);
-                gtk_style_context_add_class (gtk_widget_get_style_context (image), "dim-label");
-                gtk_box_pack_start (GTK_BOX (row), image, FALSE, TRUE, 0);
-        }
-
-        gtk_widget_show_all (row);
-        gtk_container_add (GTK_CONTAINER (priv->input_list), row);
-        priv->selected_input_sorted = g_list_prepend (priv->selected_input_sorted, row);
-
-        g_object_set_data (G_OBJECT (row), "label", label);
-        g_object_set_data (G_OBJECT (row), "type", (gpointer)type);
-        g_object_set_data_full (G_OBJECT (row), "id", g_strdup (id), g_free);
-        if (app_info) {
-                g_object_set_data_full (G_OBJECT (row), "app-info", g_object_ref (app_info), g_object_unref);
-        }
-
-        priv->n_input_rows += 1;
-        adjust_input_list_scrolling (self);
-
-        return row;
-}
-
-static void
-add_input_source (GisKeyboardPage *self,
-                  const gchar     *type,
-                  const gchar     *id)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        const gchar *name;
-        gchar *display_name;
-        GDesktopAppInfo *app_info;
-
-        display_name = NULL;
-        app_info = NULL;
-
-        if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
-                gnome_xkb_info_get_layout_info (priv->xkb_info, id, &name, NULL, NULL, NULL);
-                if (!name) {
-                        g_warning ("Couldn't find XKB input source '%s'", id);
-                        return;
-                }
-                display_name = g_strdup (name);
-                type = INPUT_SOURCE_TYPE_XKB;
-#ifdef HAVE_IBUS
-        } else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
-                IBusEngineDesc *engine_desc = NULL;
-
-                if (priv->ibus_engines)
-                        engine_desc = g_hash_table_lookup (priv->ibus_engines, id);
-                if (engine_desc)
-                        display_name = engine_get_display_name (engine_desc);
-
-                app_info = setup_app_info_for_id (id);
-                type = INPUT_SOURCE_TYPE_IBUS;
-#endif
-        } else {
-                g_warning ("Unhandled input source type '%s'", type);
-                return;
-        }
-
-        add_input_row (self, type, id, display_name ? display_name : id, app_info);
-        g_free (display_name);
-        g_clear_object (&app_info);
-}
-
-static void
-add_input_sources (GisKeyboardPage *self,
-                   GVariant        *sources)
-{
-        GVariantIter iter;
-        const gchar *type;
-        const gchar *id;
-
-        g_variant_iter_init (&iter, sources);
-        while (g_variant_iter_next (&iter, "(&s&s)", &type, &id))
-                add_input_source (self, type, id);
-}
-
-static void
-add_input_sources_from_settings (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GVariant *sources;
-        sources = g_settings_get_value (priv->input_settings, "sources");
-        add_input_sources (self, sources);
-        g_variant_unref (sources);
-}
-
-static void
-clear_input_sources (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GList *list, *l;
-        list = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
-        for (l = list; l; l = l->next) {
-                gtk_container_remove (GTK_CONTAINER (priv->input_list), GTK_WIDGET (l->data));
-        }
-        g_list_free (list);
-        g_clear_pointer (&priv->selected_input_sorted, g_list_free);
-
-        priv->n_input_rows = 0;
-        adjust_input_list_scrolling (self);
-}
-
-static void
-select_by_id (GtkWidget   *row,
-              gpointer     data)
-{
-        const gchar *id = data;
-        const gchar *row_id;
-
-        row_id = (const gchar *)g_object_get_data (G_OBJECT (row), "id");
-        if (g_strcmp0 (row_id, id) == 0)
-                egg_list_box_select_child (EGG_LIST_BOX (gtk_widget_get_parent (row)), row);
-}
-
-static void
-select_input (GisKeyboardPage *self,
-              const gchar   *id)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-
-        gtk_container_foreach (GTK_CONTAINER (priv->input_list),
-                               select_by_id, (gpointer)id);
-}
-
-static void
-input_sources_changed (GSettings     *settings,
-                       const gchar   *key,
-                       GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *selected;
-        gchar *id = NULL;
-
-        selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->input_list));
-        if (selected)
-                id = g_strdup (g_object_get_data (G_OBJECT (selected), "id"));
-        clear_input_sources (self);
-        add_input_sources_from_settings (self);
-        if (id) {
-                select_input (self, id);
-                g_free (id);
-        }
-}
-
-static void
-current_input_source_changed (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GList *all_inputs;
-        GtkWidget *current_input;
-        guint current_input_index;
-
-        current_input_index = g_settings_get_uint (priv->input_settings, KEY_CURRENT_INPUT_SOURCE);
-        all_inputs = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
-        current_input = g_list_nth_data (all_inputs, current_input_index);
-        if (current_input)
-                egg_list_box_select_child (EGG_LIST_BOX (priv->input_list), current_input);
-
-        g_list_free (all_inputs);
+       G_OBJECT_CLASS (gis_keyboard_page_parent_class)->finalize (object);
 }
 
-
 static void
-update_buttons (GisKeyboardPage *self)
+set_input_settings (GisKeyboardPage *self)
 {
         GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *selected;
-        GList *children;
-        gboolean multiple_sources;
-
-        children = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
-        multiple_sources = g_list_next (children) != NULL;
-        g_list_free (children);
-
-        selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->input_list));
-        if (selected == NULL) {
-                gtk_widget_set_visible (priv->show_config, FALSE);
-                gtk_widget_set_sensitive (priv->remove_input, FALSE);
-                gtk_widget_set_sensitive (priv->show_layout, FALSE);
-        } else {
-                GDesktopAppInfo *app_info;
-
-                app_info = (GDesktopAppInfo *)g_object_get_data (G_OBJECT (selected), "app-info");
-
-                gtk_widget_set_visible (priv->show_config, app_info != NULL);
-                gtk_widget_set_sensitive (priv->show_layout, TRUE);
-                gtk_widget_set_sensitive (priv->remove_input, multiple_sources);
-        }
-}
+        GVariantBuilder builder;
 
-static void
-update_current_input (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *selected;
-        GList *children;
-        guint index;
+        g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)"));
+       g_variant_builder_add (&builder, "(ss)",
+               cc_input_chooser_get_input_type (CC_INPUT_CHOOSER (priv->input_chooser)),
+               cc_input_chooser_get_input_id (CC_INPUT_CHOOSER (priv->input_chooser)));
 
-        selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->input_list));
-        if (selected) {
-                children = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
-                index = g_list_index (children, selected);
-                g_settings_set_uint (priv->input_settings, KEY_CURRENT_INPUT_SOURCE, index);
-                g_settings_apply (priv->input_settings);
-                g_list_free (children);
+       g_settings_set_value (priv->input_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder));
+       g_settings_set_uint (priv->input_settings, KEY_CURRENT_INPUT_SOURCE, 0);
 
-                /* Put the selected input in the head */
-                priv->selected_input_sorted = g_list_remove (priv->selected_input_sorted, selected);
-                priv->selected_input_sorted = g_list_prepend (priv->selected_input_sorted, selected);
-        }
+       g_settings_apply (priv->input_settings);
 }
 
 static void
-set_input_settings (GisKeyboardPage *self)
+set_localed_input (GisKeyboardPage *self)
 {
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        const gchar *type;
-        const gchar *id;
-        GVariantBuilder builder;
-        GVariant *old_sources;
-        const gchar *old_current_type;
-        const gchar *old_current_id;
-        guint old_current;
-        guint old_n_sources;
-        guint index;
-        GList *list, *l;
+       GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
+       const gchar *layout, *variant;
 
-        old_sources = g_settings_get_value (priv->input_settings, KEY_INPUT_SOURCES);
-        old_current = g_settings_get_uint (priv->input_settings, KEY_CURRENT_INPUT_SOURCE);
-        old_n_sources = g_variant_n_children (old_sources);
+       cc_input_chooser_get_layout (CC_INPUT_CHOOSER (priv->input_chooser), &layout, &variant);
 
-        if (old_n_sources > 0 && old_current < old_n_sources) {
-                g_variant_get_child (old_sources, old_current,
-                                     "(&s&s)", &old_current_type, &old_current_id);
-        } else {
-                old_current_type = "";
-                old_current_id = "";
-        }
-
-        g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)"));
-        index = 0;
-        list = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
-        for (l = list; l; l = l->next) {
-                type = (const gchar *)g_object_get_data (G_OBJECT (l->data), "type");
-                id = (const gchar *)g_object_get_data (G_OBJECT (l->data), "id");
-                if (index != old_current &&
-                    g_str_equal (type, old_current_type) &&
-                    g_str_equal (id, old_current_id)) {
-                        g_settings_set_uint (priv->input_settings, KEY_CURRENT_INPUT_SOURCE, index);
-                }
-                g_variant_builder_add (&builder, "(ss)", type, id);
-                index += 1;
-        }
-        g_list_free (list);
-
-        g_settings_set_value (priv->input_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder));
-        g_settings_apply (priv->input_settings);
-
-        g_variant_unref (old_sources);
+        g_dbus_proxy_call (priv->localed,
+                           "SetX11Keyboard",
+                           g_variant_new ("(ssssbb)", layout, "", variant, "", TRUE, TRUE),
+                           G_DBUS_CALL_FLAGS_NONE,
+                           -1, NULL, NULL, NULL);
 }
 
-
-static void set_localed_input (GisKeyboardPage *self);
-
 static void
 change_locale_permission_acquired (GObject      *source,
-                                   GAsyncResult *res,
-                                   gpointer      data)
+                                  GAsyncResult *res,
+                                  gpointer      data)
 {
-  GisKeyboardPage *page = GIS_KEYBOARD_PAGE (data);
-  GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (page);
-  GError *error = NULL;
-  gboolean allowed;
+       GisKeyboardPage *page = GIS_KEYBOARD_PAGE (data);
+       GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (page);
+       GError *error = NULL;
+       gboolean allowed;
 
-  allowed = g_permission_acquire_finish (priv->permission, res, &error);
-  if (error) {
-      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-        g_warning ("Failed to acquire permission: %s\n", error->message);
-      g_error_free (error);
-      return;
-  }
+       allowed = g_permission_acquire_finish (priv->permission, res, &error);
+       if (error) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                       g_warning ("Failed to acquire permission: %s\n", error->message);
+               g_error_free (error);
+               return;
+       }
 
-  if (allowed)
-    set_localed_input (GIS_KEYBOARD_PAGE (data));
+       if (allowed)
+               set_localed_input (GIS_KEYBOARD_PAGE (data));
 }
 
-
 static void
 update_input (GisKeyboardPage *self)
 {
-  GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
+       GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
 
-  set_input_settings (self);
+       set_input_settings (self);
 
-  if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER) {
-      if (g_permission_get_allowed (priv->permission)) {
-          set_localed_input (self);
-      }
-      else if (g_permission_get_can_acquire (priv->permission)) {
-          g_permission_acquire_async (priv->permission,
-                                      NULL,
-                                      change_locale_permission_acquired,
-                                      self);
-      }
-  }
+       if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER) {
+               if (g_permission_get_allowed (priv->permission)) {
+                       set_localed_input (self);
+               } else if (g_permission_get_can_acquire (priv->permission)) {
+                       g_permission_acquire_async (priv->permission,
+                                                   NULL,
+                                                   change_locale_permission_acquired,
+                                                   self);
+               }
+       }
 }
 
 static gboolean
-input_source_already_added (GisKeyboardPage *self,
-                            const gchar   *id)
+gis_keyboard_page_apply (GisPage      *page,
+                         GCancellable *cancellable)
 {
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GList *list, *l;
-        gboolean retval = FALSE;
-
-        list = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
-        for (l = list; l; l = l->next)
-                if (g_str_equal (id, (const gchar *) g_object_get_data (G_OBJECT (l->data), "id"))) {
-                        retval = TRUE;
-                        break;
-                }
-        g_list_free (list);
-
-        return retval;
+       update_input (GIS_KEYBOARD_PAGE (page));
+        return FALSE;
 }
 
 static void
-input_response (GtkWidget *chooser, gint response_id, gpointer data)
+localed_proxy_ready (GObject      *source,
+                    GAsyncResult *res,
+                    gpointer      data)
 {
        GisKeyboardPage *self = data;
-        gchar *type;
-        gchar *id;
-        gchar *name;
-        GDesktopAppInfo *app_info = NULL;
+       GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
+       GDBusProxy *proxy;
+       GError *error = NULL;
 
-        if (response_id == GTK_RESPONSE_OK) {
-                if (cc_input_chooser_get_selected (chooser, &type, &id, &name) &&
-                    !input_source_already_added (self, id)) {
-                        if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
-                                g_free (type);
-                                type = INPUT_SOURCE_TYPE_IBUS;
-#ifdef HAVE_IBUS
-                                app_info = setup_app_info_for_id (id);
-#endif
-                        } else {
-                                g_free (type);
-                                type = INPUT_SOURCE_TYPE_XKB;
-                        }
+       proxy = g_dbus_proxy_new_finish (res, &error);
 
-                        add_input_row (self, type, id, name, app_info);
-                        update_buttons (self);
-                        update_input (self);
-                        select_input (self, id);
+       if (!proxy) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                       g_warning ("Failed to contact localed: %s\n", error->message);
+               g_error_free (error);
+               return;
+       }
 
-                        g_free (id);
-                        g_free (name);
-                        g_clear_object (&app_info);
-                }
-        }
-        gtk_widget_destroy (chooser);
-        g_object_set_data (G_OBJECT (self), "input-chooser", NULL);
+       priv->localed = proxy;
 }
 
 static void
-show_input_chooser (GisKeyboardPage *self)
+input_confirmed (CcInputChooser  *chooser,
+                 GisKeyboardPage *self)
 {
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *chooser;
-        GtkWidget *toplevel;
-
-        toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
-        chooser = cc_input_chooser_new (GTK_WINDOW (toplevel),
-                                        priv->xkb_info,
-#ifdef HAVE_IBUS
-                                        priv->ibus_engines
-#else
-                                        NULL
-#endif
-                );
-        g_signal_connect (chooser, "response",
-                          G_CALLBACK (input_response), self);
-        gtk_window_present (GTK_WINDOW (chooser));
-
-        g_object_set_data (G_OBJECT (self), "input-chooser", chooser);
-}
-
-static void
-add_input (GisKeyboardPage *self)
-{
-        show_input_chooser (self);
+        gis_assistant_next_page (gis_driver_get_assistant (GIS_PAGE (self)->driver));
 }
 
 static void
-do_remove_selected_input (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *selected;
-
-        selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->input_list));
-        if (selected == NULL)
-                return;
-
-        priv->selected_input_sorted = g_list_delete_link (priv->selected_input_sorted,
-                                                          priv->selected_input_sorted);
-        gtk_container_remove (GTK_CONTAINER (priv->input_list), selected);
-        if (priv->selected_input_sorted)
-                egg_list_box_select_child (EGG_LIST_BOX (priv->input_list), 
priv->selected_input_sorted->data);
-        else
-                egg_list_box_select_child (EGG_LIST_BOX (priv->input_list), NULL);
-
-        priv->n_input_rows -= 1;
-        adjust_input_list_scrolling (self);
-
-        update_buttons (self);
-        update_input (self);
-}
-
-static void
-remove_selected_input (GisKeyboardPage *self)
-{
-        do_remove_selected_input (self);
-}
-
-static void
-show_selected_settings (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *selected;
-        GdkAppLaunchContext *ctx;
-        GDesktopAppInfo *app_info;
-        const gchar *id;
-        GError *error = NULL;
-
-        selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->input_list));
-        if (selected == NULL)
-                return;
-
-        app_info = (GDesktopAppInfo *)g_object_get_data (G_OBJECT (selected), "app-info");
-        if  (app_info == NULL)
-                return;
-
-        ctx = gdk_display_get_app_launch_context (gdk_display_get_default ());
-        gdk_app_launch_context_set_timestamp (ctx, gtk_get_current_event_time ());
-
-        id = (const gchar *)g_object_get_data (G_OBJECT (selected), "id");
-        g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (ctx),
-                                     "IBUS_ENGINE_NAME", id);
-
-        if (!g_app_info_launch (G_APP_INFO (app_info), NULL, G_APP_LAUNCH_CONTEXT (ctx), &error)) {
-                g_warning ("Failed to launch input source setup: %s", error->message);
-                g_error_free (error);
-        }
-
-        g_object_unref (ctx);
-}
-
-static void
-show_selected_layout (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GtkWidget *selected;
-        const gchar *type;
-        const gchar *id;
-        const gchar *layout;
-        const gchar *variant;
-        gchar *commandline;
-        gchar **argv = NULL;
-
-        selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->input_list));
-        if (selected == NULL)
-                return;
-
-        type = (const gchar *)g_object_get_data (G_OBJECT (selected), "type");
-        id = (const gchar *)g_object_get_data (G_OBJECT (selected), "id");
-
-        if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
-                gnome_xkb_info_get_layout_info (priv->xkb_info,
-                                                id, NULL, NULL,
-                                                &layout, &variant);
-
-                if (!layout || !layout[0]) {
-                        g_warning ("Couldn't find XKB input source '%s'", id);
-                        return;
-                }
-#ifdef HAVE_IBUS
-        } else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
-                IBusEngineDesc *engine_desc = NULL;
-
-                if (priv->ibus_engines)
-                        engine_desc = g_hash_table_lookup (priv->ibus_engines, id);
-
-                if (engine_desc) {
-                        layout = ibus_engine_desc_get_layout (engine_desc);
-                        variant = "";
-                } else {
-                        g_warning ("Couldn't find IBus input source '%s'", id);
-                        return;
-                }
-#endif
-        } else {
-                g_warning ("Unhandled input source type '%s'", type);
-                return;
-        }
-
-        if (variant[0])
-                commandline = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"",
-                                               layout, variant);
-        else
-                commandline = g_strdup_printf ("gkbd-keyboard-display -l %s",
-                                               layout);
-
-        if (!g_shell_parse_argv (commandline,
-                            NULL,
-                            &argv,
-                            NULL))
-          goto out;
-
-        if (priv->gkbd_pid)
-          {
-            kill (priv->gkbd_pid, 9);
-            priv->gkbd_pid = 0;
-          }
-
-        g_spawn_async (NULL,
-                       argv,
-                       NULL,
-                       G_SPAWN_SEARCH_PATH,
-                       NULL,
-                       NULL,
-                       &priv->gkbd_pid,
-                       NULL);
-        g_strfreev (argv);
-  out:
-        g_free (commandline);
-}
-
-static void
-detector_response (GtkDialog *detector, gint response_id, gpointer data)
-{
-  GisKeyboardPage *self = data;
-  const char *type;
-  char *id;
-  char *name;
-
-  if (response_id == GTK_RESPONSE_OK)
-    {
-      if (cc_keyboard_query_get_selected (CC_KEYBOARD_QUERY (detector), &id, &name))
-        {
-          if (name == NULL)
-            name = g_strdup (id);
-          if (!input_source_already_added (self, id))
-            {
-              type = INPUT_SOURCE_TYPE_XKB;
-              add_input_row (self, type, id, name, NULL);
-              update_buttons (self);
-              update_input (self);
-            }
-          select_input (self, id);
-
-          g_free (id);
-          g_free (name);
-        }
-    }
-  gtk_widget_destroy (GTK_WIDGET (detector));
-}
-
-static void
-show_keyboard_detector (GisKeyboardPage *self)
-{
-  GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-  GtkWidget *detector;
-  GtkWidget *toplevel;
-
-  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
-  detector = cc_keyboard_query_new (GTK_WINDOW (toplevel), priv->xkb_info);
-  g_signal_connect (detector, "response", G_CALLBACK (detector_response), self);
-  cc_keyboard_query_run (CC_KEYBOARD_QUERY (detector));
-}
-
-static void
-add_default_input_source_for_locale (GisKeyboardPage *self)
-{
-        const gchar *locale;
-        const gchar *type;
-        const gchar *id;
-
-        locale = gis_driver_get_user_language (GIS_PAGE (self)->driver);
-
-        if (!gnome_get_input_source_from_locale (locale, &type, &id))
-                return;
-
-        add_input_source (self, type, id);
-}
-
-static void
-setup_input_section (GisKeyboardPage *self)
-{
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-
-        priv->input_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR);
-        g_settings_delay (priv->input_settings);
-
-        priv->xkb_info = gnome_xkb_info_new ();
-
-#ifdef HAVE_IBUS
-        ibus_init ();
-        if (!priv->ibus) {
-                priv->ibus = ibus_bus_new_async ();
-                if (ibus_bus_is_connected (priv->ibus))
-                        fetch_ibus_engines (self);
-                else
-                        g_signal_connect_swapped (priv->ibus, "connected",
-                                                  G_CALLBACK (fetch_ibus_engines), self);
-        }
-        maybe_start_ibus ();
-#endif
-
-        priv->input_section = WID ("input_section");
-        priv->input_list = WID ("input_list");
-        priv->add_input = WID ("input_source_add");
-        priv->remove_input = WID ("input_source_remove");
-        priv->show_config = WID ("input_source_config");
-        priv->show_layout = WID ("input_source_layout");
-        priv->auto_detect = WID ("input_auto_detect");
-        priv->input_scrolledwindow = WID ("input_scrolledwindow");
-
-        g_signal_connect_swapped (priv->add_input, "clicked",
-                                  G_CALLBACK (add_input), self);
-        g_signal_connect_swapped (priv->remove_input, "clicked",
-                                  G_CALLBACK (remove_selected_input), self);
-        g_signal_connect_swapped (priv->show_config, "clicked",
-                                  G_CALLBACK (show_selected_settings), self);
-        g_signal_connect_swapped (priv->show_layout, "clicked",
-                                  G_CALLBACK (show_selected_layout), self);
-        g_signal_connect_swapped (priv->auto_detect, "clicked",
-                                  G_CALLBACK (show_keyboard_detector), self);
-
-        egg_list_box_set_selection_mode (EGG_LIST_BOX (priv->input_list),
-                                         GTK_SELECTION_SINGLE);
-        egg_list_box_set_separator_funcs (EGG_LIST_BOX (priv->input_list),
-                                          update_separator_func,
-                                          NULL, NULL);
-        g_signal_connect_swapped (priv->input_list, "child-selected",
-                                  G_CALLBACK (update_buttons), self);
-
-        g_signal_connect_swapped (priv->input_list, "child-selected",
-                                  G_CALLBACK (update_current_input), self);
-
-        g_signal_connect (priv->input_settings, "changed::" KEY_INPUT_SOURCES,
-                          G_CALLBACK (input_sources_changed), self);
-
-        g_signal_connect_swapped (priv->input_settings, "changed::" KEY_CURRENT_INPUT_SOURCE,
-                                  G_CALLBACK (current_input_source_changed), self);
-
-        add_default_input_source_for_locale (self);
-        set_input_settings (self);
-        current_input_source_changed (self);
-}
-
-static void
-add_input_sources_from_localed (GisKeyboardPage *self)
+gis_keyboard_page_constructed (GObject *object)
 {
+        GisKeyboardPage *self = GIS_KEYBOARD_PAGE (object);
         GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GVariant *v;
-        const gchar *s;
-        gchar **layouts = NULL;
-        gchar **variants = NULL;
-        gint i, n;
 
-        if (!priv->localed)
-                return;
+       g_type_ensure (CC_TYPE_INPUT_CHOOSER);
 
-        v = g_dbus_proxy_get_cached_property (priv->localed, "X11Layout");
-        if (v) {
-                s = g_variant_get_string (v, NULL);
-                layouts = g_strsplit (s, ",", -1);
-                g_variant_unref (v);
-        }
-
-        v = g_dbus_proxy_get_cached_property (priv->localed, "X11Variant");
-        if (v) {
-                s = g_variant_get_string (v, NULL);
-                if (s && *s)
-                        variants = g_strsplit (s, ",", -1);
-                g_variant_unref (v);
-        }
+        G_OBJECT_CLASS (gis_keyboard_page_parent_class)->constructed (object);
 
-        if (variants && variants[0])
-                n = MIN (g_strv_length (layouts), g_strv_length (variants));
-        else if (layouts && layouts[0])
-                n = g_strv_length (layouts);
-        else
-                n = 0;
+        g_signal_connect (priv->input_chooser, "confirm",
+                          G_CALLBACK (input_confirmed), self);
 
-        for (i = 0; i < n && layouts[i][0]; i++) {
-                const gchar *name;
-                gchar *id;
+       priv->input_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR);
+       g_settings_delay (priv->input_settings);
 
-                if (variants && variants[i] && variants[i][0])
-                        id = g_strdup_printf ("%s+%s", layouts[i], variants[i]);
-                else
-                        id = g_strdup (layouts[i]);
+       priv->cancellable = g_cancellable_new ();
 
-                if (!input_source_already_added (self, id)) {
-                        gnome_xkb_info_get_layout_info (priv->xkb_info, id, &name, NULL, NULL, NULL);
-                        add_input_row (self, INPUT_SOURCE_TYPE_XKB, id, name ? name : id, NULL);
-                }
+       g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+                                 G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
+                                 NULL,
+                                 "org.freedesktop.locale1",
+                                 "/org/freedesktop/locale1",
+                                 "org.freedesktop.locale1",
+                                 priv->cancellable,
+                                 (GAsyncReadyCallback) localed_proxy_ready,
+                                 self);
 
-                g_free (id);
-        }
+       /* If we're in new user mode then we're manipulating system settings */
+       if (gis_driver_get_mode (GIS_PAGE (self)->driver) == GIS_DRIVER_MODE_NEW_USER)
+               priv->permission = polkit_permission_new_sync ("org.freedesktop.locale1.set-keyboard", NULL, 
NULL, NULL);
 
-        g_strfreev (variants);
-        g_strfreev (layouts);
+        gis_page_set_complete (GIS_PAGE (self), TRUE);
+        gtk_widget_show (GTK_WIDGET (self));
 }
 
 static void
-set_localed_input (GisKeyboardPage *self)
+gis_keyboard_page_locale_changed (GisPage *page)
 {
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GString *layouts;
-        GString *variants;
-        const gchar *type, *id;
-        GList *list, *li;
-        const gchar *l, *v;
-
-        layouts = g_string_new ("");
-        variants = g_string_new ("");
-
-        list = gtk_container_get_children (GTK_CONTAINER (priv->input_list));
-        for (li = list; li; li = li->next) {
-                type = (const gchar *)g_object_get_data (G_OBJECT (li->data), "type");
-                id = (const gchar *)g_object_get_data (G_OBJECT (li->data), "id");
-                if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS))
-                        continue;
-
-                if (gnome_xkb_info_get_layout_info (priv->xkb_info, id, NULL, NULL, &l, &v)) {
-                        if (layouts->str[0]) {
-                                g_string_append_c (layouts, ',');
-                                g_string_append_c (variants, ',');
-                        }
-                        g_string_append (layouts, l);
-                        g_string_append (variants, v);
-                }
-        }
-        g_list_free (list);
-
-        g_dbus_proxy_call (priv->localed,
-                           "SetX11Keyboard",
-                           g_variant_new ("(ssssbb)", layouts->str, "", variants->str, "", TRUE, TRUE),
-                           G_DBUS_CALL_FLAGS_NONE,
-                           -1, NULL, NULL, NULL);
-
-        g_string_free (layouts, TRUE);
-        g_string_free (variants, TRUE);
+        gis_page_set_title (GIS_PAGE (page), _("Typing"));
 }
 
 static void
-localed_proxy_ready (GObject      *source,
-                     GAsyncResult *res,
-                     gpointer      data)
+gis_keyboard_page_class_init (GisKeyboardPageClass * klass)
 {
-        GisKeyboardPage *self = data;
-        GisKeyboardPagePrivate *priv = gis_keyboard_page_get_instance_private (self);
-        GDBusProxy *proxy;
-        GError *error = NULL;
-
-        proxy = g_dbus_proxy_new_finish (res, &error);
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GisPageClass * page_class = GIS_PAGE_CLASS (klass);
 
-        if (!proxy) {
-                if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-                        g_warning ("Failed to contact localed: %s\n", error->message);
-                g_error_free (error);
-                return;
-        }
+        gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), 
"/org/gnome/initial-setup/gis-keyboard-page.ui");
 
-        priv->localed = proxy;
+        gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisKeyboardPage, 
input_chooser);
 
-        add_input_sources_from_localed (self);
-        update_input (self);
-        current_input_source_changed (self);
-        update_buttons (self);
+        page_class->page_id = PAGE_ID;
+        page_class->apply = gis_keyboard_page_apply;
+        page_class->locale_changed = gis_keyboard_page_locale_changed;
+        object_class->constructed = gis_keyboard_page_constructed;
+       object_class->finalize = gis_keyboard_page_finalize;
 }
 
 static void
 gis_keyboard_page_init (GisKeyboardPage *self)
 {
         g_resources_register (keyboard_get_resource ());
+       g_type_ensure (CC_TYPE_INPUT_CHOOSER);
+
+        gtk_widget_init_template (GTK_WIDGET (self));
 }
 
 void
diff --git a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.h 
b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.h
index 798836d..832473f 100644
--- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.h
+++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.h
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Sergey Udaltsov <svu gnome org>
  *
diff --git a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.ui 
b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.ui
index b803ffc..063f6de 100644
--- a/gnome-initial-setup/pages/keyboard/gis-keyboard-page.ui
+++ b/gnome-initial-setup/pages/keyboard/gis-keyboard-page.ui
@@ -1,261 +1,60 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-     <object class="GtkBox" id="keyboard_page">
+  <template class="GisKeyboardPage" parent="GisPage">
+    <child>
+      <object class="GtkBox" id="page">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
+       <property name="halign">center</property>
+        <property name="valign">fill</property>
         <property name="orientation">vertical</property>
         <child>
-          <object class="GtkBox" id="input_section">
+          <object class="GtkImage" id="image1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="margin_left">80</property>
-            <property name="margin_right">80</property>
-            <property name="orientation">vertical</property>
-            <child>
-              <object class="GtkBox" id="input_heading_row">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="margin_bottom">6</property>
-                <child>
-                  <object class="GtkLabel" id="input_heading">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="margin_left">6</property>
-                    <property name="margin_right">6</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">Select keyboard layouts</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                      <attribute name="scale" value="1.2"/>
-                    </attributes>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-             </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkFrame" id="input_frame">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label_xalign">0</property>
-                <property name="shadow_type">in</property>
-                <child>
-                  <object class="GtkScrolledWindow" id="input_scrolledwindow">
-                    <property name="visible">True</property>
-                    <property name="hscrollbar-policy">never</property>
-                    <property name="vscrollbar-policy">never</property>
-                    <child>
-                      <object class="GtkViewport" id="input_viewport">
-                        <property name="visible">True</property>
-                        <child>
-                          <object class="EggListBox" id="input_list">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkToolbar" id="input_toolbar">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="toolbar_style">icons</property>
-                <property name="show_arrow">False</property>
-                <property name="icon_size">1</property>
-                <style>
-                  <class name="inline-toolbar"/>
-                </style>
-                <child>
-                  <object class="GtkToolItem" id="i_s_ar_item">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkBox" id="i_s_ar_box">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <child>
-                          <object class="GtkButton" id="input_source_add">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <child>
-                              <object class="GtkImage" id="i_s_a_image">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">list-add-symbolic</property>
-                                <property name="icon-size">1</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="input_source_remove">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <child>
-                              <object class="GtkImage" id="i_s_r_image">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">list-remove-symbolic</property>
-                                <property name="icon-size">1</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkSeparatorToolItem" id="sep1">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="draw">False</property>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToolItem" id="i_s_sc_item">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkBox" id="i_s_sc_box">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <child>
-                          <object class="GtkButton" id="input_source_config">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <child>
-                              <object class="GtkImage" id="i_s_sc_image">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">emblem-system-symbolic</property>
-                                <property name="icon-size">1</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToolItem" id="i_s_sl_item">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <child>
-                      <object class="GtkBox" id="i_s_sl_box">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <child>
-                          <object class="GtkButton" id="input_source_layout">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <child>
-                              <object class="GtkImage" id="i_s_sl_image">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">input-keyboard-symbolic</property>
-                                <property name="icon-size">1</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">2</property>
-              </packing>
-            </child>
-           <child>
-             <object class="GtkButtonBox" id="i_a_d_box">
-               <property name="visible">True</property>
-               <property name="can_focus">False</property>
-               <child>
-                 <object class="GtkButton" id="input_auto_detect">
-                   <property name="label" translatable="yes">Help detect my keyboard layout</property>
-                   <property name="visible">True</property>
-                   <property name="can_focus">True</property>
-                   <property name="receives_default">True</property>
-                 </object>
-                 <packing>
-                   <property name="expand">True</property>
-                   <property name="fill">True</property>
-                   <property name="position">0</property>
-                 </packing>
-               </child>
-             </object>
-             <packing>
-               <property name="expand">False</property>
-               <property name="fill">True</property>
-               <property name="padding">10</property>
-               <property name="position">3</property>
-             </packing>
-           </child>
+            <property name="margin_top">40</property>
+            <property name="pixel_size">96</property>
+            <property name="icon_name">input-keyboard-symbolic</property>
+            <style>
+              <class name="dim-label" />
+            </style>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel" id="title">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_top">18</property>
+            <property name="halign">center</property>
+            <property name="valign">start</property>
+            <property name="label" translatable="yes">Typing</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+              <attribute name="scale" value="1.8"/>
+            </attributes>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel" id="subtitle">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_top">6</property>
+            <property name="label" translatable="yes">Select your keyboard layout or an input 
method.</property>
+            <property name="justify">left</property>
+            <property name="wrap">True</property>
+            <property name="max-width-chars">50</property>
+          </object>
+        </child>
+        <child>
+          <object class="CcInputChooser" id="input_chooser">
+            <property name="margin_top">18</property>
+            <property name="margin_bottom">18</property>
+            <property name="visible">True</property>
+            <property name="halign">center</property>
+            <property name="valign">start</property>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
         </child>
       </object>
+    </child>
+  </template>
 </interface>
diff --git a/gnome-initial-setup/pages/keyboard/input-chooser.ui 
b/gnome-initial-setup/pages/keyboard/input-chooser.ui
index 49be542..01b2bb0 100644
--- a/gnome-initial-setup/pages/keyboard/input-chooser.ui
+++ b/gnome-initial-setup/pages/keyboard/input-chooser.ui
@@ -1,81 +1,37 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0"?>
 <interface>
-  <!-- interface-requires gtk+ 3.0 -->
-  <object class="GtkDialog" id="input-dialog">
-    <property name="title" translatable="yes">Add a Keyboard Layout</property>
-    <property name="default_height">350</property>
-    <property name="modal">True</property>
-    <property name="destroy_with_parent">True</property>
-    <property name="resizable">True</property>
-    <child internal-child="vbox">
-      <object class="GtkBox" id="vbox">
+  <requires lib="gtk+" version="3.0"/>
+  <template class="CcInputChooser" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">10</property>
+    <child>
+      <object class="GtkScrolledWindow" id="scrolled_window">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
-        <property name="spacing">0</property>
+        <property name="hscrollbar-policy">never</property>
+        <property name="vscrollbar-policy">never</property>
+        <property name="shadow-type">in</property>
         <child>
-          <object class="GtkScrolledWindow" id="scrolledwindow">
+          <object class="GtkViewport" id="viewport">
             <property name="visible">True</property>
-            <property name="hscrollbar-policy">never</property>
-            <property name="vscrollbar-policy">never</property>
-            <property name="shadow-type">in</property>
-            <property name="margin-left">6</property>
-            <property name="margin-right">6</property>
-            <property name="margin-top">6</property>
-            <property name="margin-bottom">6</property>
             <child>
-              <object class="GtkViewport" id="viewport">
+              <object class="GtkListBox" id="input_list">
                 <property name="visible">True</property>
-                <child>
-                  <object class="EggListBox" id="list">
-                    <property name="visible">True</property>
-                    <property name="can-focus">True</property>
-                    <property name="vexpand">True</property>
-                    <property name="halign">fill</property>
-                    <property name="valign">fill</property>
-                  </object>
-                </child>
-              </object>
-            </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkSearchEntry" id="filter-entry">
-            <property name="visible">False</property>
-            <property name="hexpand">True</property>
-            <property name="margin-left">6</property>
-            <property name="margin-right">6</property>
-            <property name="margin-top">6</property>
-            <property name="margin-bottom">6</property>
-          </object>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkButtonBox" id="action-area">
-            <property name="visible">True</property>
-            <property name="orientation">horizontal</property>
-            <child>
-              <object class="GtkButton" id="cancel-button">
-                <property name="visible">True</property>
-                <property name="label">gtk-cancel</property>
-                <property name="use_stock">True</property>
-                <property name="use_underline" >True</property>
-              </object>
-            </child>
-            <child>
-              <object class="GtkButton" id="add-button">
-                <property name="visible">True</property>
-                <property name="sensitive">False</property>
-                <property name="label">gtk-add</property>
-                <property name="use_stock">True</property>
-                <property name="use_underline" >True</property>
+                <property name="can-focus">True</property>
+                <property name="vexpand">True</property>
+                <property name="halign">fill</property>
+                <property name="valign">fill</property>
               </object>
             </child>
           </object>
         </child>
       </object>
     </child>
-    <action-widgets>
-      <action-widget response="-5">add-button</action-widget>
-      <action-widget response="-6">cancel-button</action-widget>
-    </action-widgets>
-  </object>
+    <child>
+      <object class="GtkSearchEntry" id="filter_entry">
+        <property name="visible">False</property>
+        <property name="hexpand">True</property>
+      </object>
+    </child>
+  </template>
 </interface>


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