[gnome-control-center] Wip: new region panel



commit d3852fc8316d64204c1b94b5cb6a24c044ef2db1
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Jan 27 23:18:24 2013 -0500

    Wip: new region panel
    
    Still missing:
    - restart session notification
    - login screen mode

 panels/region/Makefile.am              |   16 +-
 panels/region/cc-format-chooser.c      |  521 ++++++++++++++++++
 panels/region/cc-format-chooser.h      |   39 ++
 panels/region/cc-ibus-utils.c          |   41 ++
 panels/region/cc-ibus-utils.h          |   31 +
 panels/region/cc-input-chooser.c       |  326 +++++++++++
 panels/region/cc-input-chooser.h       |   42 ++
 panels/region/cc-input-options.c       |  203 +++++++
 panels/region/cc-input-options.h       |   35 ++
 panels/region/cc-region-panel.c        |  936 +++++++++++++++++++++++++++-----
 panels/region/format-chooser.ui        |  344 ++++++++++++
 panels/region/input-options.ui         |  225 ++++++++
 panels/region/region.gresource.xml     |    5 +-
 panels/region/region.ui                |  338 ++++++++++++-
 panels/region/supported-ibus-engines.h |  212 +++++++
 15 files changed, 3161 insertions(+), 153 deletions(-)
---
diff --git a/panels/region/Makefile.am b/panels/region/Makefile.am
index 8f6a6cb..b33deec 100644
--- a/panels/region/Makefile.am
+++ b/panels/region/Makefile.am
@@ -18,14 +18,14 @@ libregion_la_SOURCES =      \
        $(BUILT_SOURCES) \
        cc-region-panel.c \
        cc-region-panel.h \
-       gnome-region-panel-formats.c \
-       gnome-region-panel-formats.h \
-       gnome-region-panel-lang.c \
-       gnome-region-panel-lang.h \
-       gnome-region-panel-system.c \
-       gnome-region-panel-system.h \
-       gnome-region-panel-input.c \
-       gnome-region-panel-input.h \
+       cc-format-chooser.c \
+       cc-format-chooser.h \
+       cc-input-options.c \
+       cc-input-options.h \
+       cc-input-chooser.c \
+       cc-input-chooser.h \
+       cc-ibus-utils.c \
+       cc-ibus-utils.h \
        $(NULL)
 
 libregion_la_LIBADD = $(PANEL_LIBS) $(REGION_PANEL_LIBS) $(builddir)/../common/liblanguage.la
diff --git a/panels/region/cc-format-chooser.c b/panels/region/cc-format-chooser.c
new file mode 100644
index 0000000..cde9e77
--- /dev/null
+++ b/panels/region/cc-format-chooser.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2013 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ *     Matthias Clasen
+ */
+
+#define _GNU_SOURCE
+#include <config.h>
+#include "cc-format-chooser.h"
+
+#include <locale.h>
+#include <langinfo.h>
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "egg-list-box/egg-list-box.h"
+
+#include "cc-common-language.h"
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-languages.h>
+
+
+typedef struct {
+        GtkWidget *dialog;
+        GtkWidget *no_results;
+        GtkWidget *more_item;
+        GtkWidget *filter_entry;
+        GtkWidget *list;
+        GtkWidget *scrolledwindow;
+        GtkWidget *full_date;
+        GtkWidget *medium_date;
+        GtkWidget *short_date;
+        GtkWidget *time;
+        GtkWidget *number;
+        GtkWidget *measurement;
+        GtkWidget *paper;
+        gboolean adding;
+        gboolean showing_extra;
+        gchar *region;
+} CcFormatChooserPrivate;
+
+#define GET_PRIVATE(chooser) ((CcFormatChooserPrivate *) g_object_get_data (G_OBJECT (chooser), "private"))
+
+static void
+display_date (GtkWidget *label, GDateTime *dt, const gchar *format)
+{
+        gchar *s;
+        s = g_date_time_format (dt, format);
+        s = g_strstrip (s);
+        gtk_label_set_text (GTK_LABEL (label), s);
+        g_free (s);
+}
+
+static void
+update_format_examples (GtkDialog *chooser)
+{
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+        gchar *locale;
+        GDateTime *dt;
+        gchar *s;
+        const gchar *fmt;
+        GtkPaperSize *paper;
+
+        locale = g_strdup (setlocale (LC_TIME, NULL));
+        setlocale (LC_TIME, priv->region);
+
+        dt = g_date_time_new_now_local ();
+        display_date (priv->full_date, dt, "%A %e %B %Y");
+        display_date (priv->medium_date, dt, "%e %b %Y");
+        display_date (priv->short_date, dt, "%x");
+        display_date (priv->time, dt, "%X");
+
+        setlocale (LC_TIME, locale);
+        g_free (locale);
+
+        locale = g_strdup (setlocale (LC_NUMERIC, NULL));
+        setlocale (LC_NUMERIC, priv->region);
+
+        s = g_strdup_printf ("%'.2f", 123456789.00);
+        gtk_label_set_text (GTK_LABEL (priv->number), s);
+        g_free (s);
+
+        setlocale (LC_NUMERIC, locale);
+        g_free (locale);
+
+#if 0
+        locale = g_strdup (setlocale (LC_MONETARY, NULL));
+        setlocale (LC_MONETARY, priv->region);
+
+        num_info = localeconv ();
+        if (num_info != NULL) {
+                gtk_label_set_text (GTK_LABEL (priv->currency), num_info->currency_symbol);
+        }
+
+        setlocale (LC_MONETARY, locale);
+        g_free (locale);
+#endif
+
+#ifdef LC_MEASUREMENT
+        locale = g_strdup (setlocale (LC_MEASUREMENT, NULL));
+        setlocale (LC_MEASUREMENT, priv->region);
+
+        fmt = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
+        if (fmt && *fmt == 2)
+                gtk_label_set_text (GTK_LABEL (priv->measurement), _("Imperial"));
+        else
+                gtk_label_set_text (GTK_LABEL (priv->measurement), _("Metric"));
+
+        setlocale (LC_MEASUREMENT, locale);
+        g_free (locale);
+#endif
+
+#ifdef LC_PAPER
+        locale = g_strdup (setlocale (LC_PAPER, NULL));
+        setlocale (LC_PAPER, priv->region);
+
+        paper = gtk_paper_size_new (gtk_paper_size_get_default ());
+        gtk_label_set_text (GTK_LABEL (priv->paper), gtk_paper_size_get_display_name (paper));
+        gtk_paper_size_free (paper);
+
+        setlocale (LC_PAPER, locale);
+        g_free (locale);
+#endif
+}
+
+static void
+set_locale_id (GtkDialog   *chooser,
+               const gchar *locale_id)
+{
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+        GList *children, *l;
+
+        children = gtk_container_get_children (GTK_CONTAINER (priv->list));
+        for (l = children; l; l = l->next) {
+                GtkWidget *row = l->data;
+                GtkWidget *check = g_object_get_data (G_OBJECT (row), "check");
+                const gchar *region = g_object_get_data (G_OBJECT (row), "locale-id");
+                if (check == NULL || region == NULL)
+                        continue;
+
+                if (strcmp (locale_id, region) == 0) {
+                        gboolean is_extra;
+
+                        /* mark as selected */
+                        gtk_image_set_from_icon_name (GTK_IMAGE (check), "object-select-symbolic", 
GTK_ICON_SIZE_MENU);
+
+                        /* make sure this row is shown */
+                        is_extra = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (row), "is-extra"));
+                        if (!priv->showing_extra && is_extra) {
+                                g_object_set_data (G_OBJECT (row), "is-extra", GINT_TO_POINTER (FALSE));
+                                egg_list_box_refilter (EGG_LIST_BOX (priv->list));
+                        }
+
+                } else {
+                        /* mark as unselected */
+                        gtk_image_clear (GTK_IMAGE (check));
+                        g_object_set (check, "icon-size", GTK_ICON_SIZE_MENU, NULL);
+                }
+        }
+        g_list_free (children);
+
+        g_free (priv->region);
+        priv->region = g_strdup (locale_id);
+
+        update_format_examples (chooser);
+}
+
+static gint
+sort_regions (gconstpointer a,
+              gconstpointer b,
+              gpointer      data)
+{
+        const gchar *la;
+        const gchar *lb;
+        gboolean iea;
+        gboolean ieb;
+
+        if (g_object_get_data (G_OBJECT (a), "locale-id") == NULL) {
+                return 1;
+        }
+        if (g_object_get_data (G_OBJECT (b), "locale-id") == NULL) {
+                return -1;
+        }
+
+        la = g_object_get_data (G_OBJECT (a), "locale-name");
+        lb = g_object_get_data (G_OBJECT (b), "locale-name");
+
+        iea = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (a), "is-extra"));
+        ieb = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (b), "is-extra"));
+
+        if (iea != ieb) {
+                return ieb - iea;
+        } else {
+                return strcmp (la, lb);
+        }
+}
+
+static GtkWidget *
+padded_label_new (char *text, gboolean narrow)
+{
+        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_widget_set_margin_left (widget, narrow ? 10 : 80);
+        gtk_widget_set_margin_right (widget, narrow ? 10 : 80);
+        gtk_box_pack_start (GTK_BOX (widget), gtk_label_new (text), FALSE, FALSE, 0);
+
+        return widget;
+}
+
+static GtkWidget *
+region_widget_new (const gchar *locale_id,
+                   gboolean     is_extra)
+{
+        gchar *locale_name;
+        GtkWidget *widget;
+        GtkWidget *check;
+
+        locale_name = gnome_get_region_from_name (locale_id, locale_id);
+
+        widget = padded_label_new (locale_name, is_extra);
+
+        check = gtk_image_new ();
+        g_object_set (check, "icon-size", GTK_ICON_SIZE_MENU, NULL);
+        gtk_box_pack_start (GTK_BOX (widget), check, FALSE, FALSE, 0);
+
+        g_object_set_data (G_OBJECT (widget), "check", check);
+        g_object_set_data_full (G_OBJECT (widget), "locale-id", g_strdup (locale_id), g_free);
+        g_object_set_data_full (G_OBJECT (widget), "locale-name", g_strdup (locale_name), g_free);
+        g_object_set_data (G_OBJECT (widget), "is-extra", GUINT_TO_POINTER (is_extra));
+
+        g_free (locale_name);
+
+        return widget;
+}
+
+static GtkWidget *
+more_widget_new (void)
+{
+        GtkWidget *widget;
+
+        widget = padded_label_new ("…", FALSE);
+        gtk_widget_set_tooltip_text (widget, _("More…"));
+        return widget;
+}
+
+static GtkWidget *
+no_results_widget_new (void)
+{
+        GtkWidget *widget;
+
+        widget = padded_label_new (_("No regions found"), TRUE);
+        gtk_widget_set_sensitive (widget, FALSE);
+        return widget;
+}
+
+static void
+add_regions (GtkDialog   *chooser,
+             gchar      **locale_ids,
+             GHashTable  *initial)
+{
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+
+        priv->adding = TRUE;
+
+        while (*locale_ids) {
+                gchar *locale_id;
+                gboolean is_initial;
+                GtkWidget *widget;
+
+                locale_id = *locale_ids;
+                locale_ids ++;
+
+                if (!cc_common_language_has_font (locale_id))
+                        continue;
+
+                is_initial = (g_hash_table_lookup (initial, locale_id) != NULL);
+                widget = region_widget_new (locale_id, !is_initial);
+                gtk_container_add (GTK_CONTAINER (priv->list), widget);
+        }
+
+        gtk_container_add (GTK_CONTAINER (priv->list), priv->more_item);
+        gtk_container_add (GTK_CONTAINER (priv->list), priv->no_results);
+
+        gtk_widget_show_all (priv->list);
+
+        priv->adding = FALSE;
+}
+
+static void
+add_all_regions (GtkDialog *chooser)
+{
+        gchar **locale_ids;
+        GHashTable *initial;
+
+        locale_ids = gnome_get_all_language_names ();
+        initial = cc_common_language_get_initial_languages ();
+        add_regions (chooser, locale_ids, initial);
+}
+
+static gboolean
+region_visible (GtkWidget *child,
+                gpointer   user_data)
+{
+        GtkDialog *chooser = user_data;
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+        gchar *locale_name;
+        const gchar *filter_contents;
+        gboolean is_extra;
+
+        if (child == priv->more_item)
+                return !priv->showing_extra;
+
+        /* We hide this in the after-refilter handler below. */
+        if (child == priv->no_results)
+                return TRUE;
+
+        is_extra = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (child), "is-extra"));
+        locale_name = g_object_get_data (G_OBJECT (child), "locale-name");
+
+        filter_contents = gtk_entry_get_text (GTK_ENTRY (priv->filter_entry));
+        if (*filter_contents && strcasestr (locale_name, filter_contents) == NULL)
+        return FALSE;
+
+        if (!priv->showing_extra && is_extra)
+                return FALSE;
+
+        return TRUE;
+}
+
+static void
+show_more (GtkDialog *chooser)
+{
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+        GtkWidget *widget;
+        gint width, height;
+
+        gtk_window_get_size (GTK_WINDOW (chooser), &width, &height);
+        gtk_widget_set_size_request (GTK_WIDGET (chooser), width, height);
+        gtk_window_set_resizable (GTK_WINDOW (chooser), TRUE);
+
+        widget = priv->scrolledwindow;
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget),
+                                        GTK_POLICY_NEVER,
+                                        GTK_POLICY_AUTOMATIC);
+
+        gtk_widget_show (priv->filter_entry);
+        gtk_widget_grab_focus (priv->filter_entry);
+
+        priv->showing_extra = TRUE;
+
+        egg_list_box_refilter (EGG_LIST_BOX (priv->list));
+}
+
+static void
+child_activated (EggListBox  *box,
+                 GtkWidget   *child,
+                 GtkDialog   *chooser)
+{
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+        gchar *new_locale_id;
+
+        if (priv->adding)
+                return;
+
+        if (child == NULL)
+                return;
+        else if (child == priv->no_results)
+                return;
+        else if (child == priv->more_item)
+                show_more (chooser);
+        else {
+                new_locale_id = g_object_get_data (G_OBJECT (child), "locale-id");
+                set_locale_id (chooser, new_locale_id);
+        }
+}
+
+typedef struct {
+        gint count;
+        GtkWidget *ignore;
+} CountChildrenData;
+
+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++;
+}
+
+static void
+end_refilter (EggListBox *list_box,
+              gpointer    user_data)
+{
+        GtkDialog *chooser = user_data;
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+        CountChildrenData data = { 0 };
+
+        data.ignore = priv->no_results;
+        gtk_container_foreach (GTK_CONTAINER (list_box),
+                               count_visible_children, &data);
+
+        gtk_widget_set_visible (priv->no_results, (data.count == 0));
+}
+
+static void
+cc_format_chooser_private_free (gpointer data)
+{
+        g_free (data);
+}
+
+#define WID(name) ((GtkWidget *) gtk_builder_get_object (builder, name))
+
+GtkWidget *
+cc_format_chooser_new (GtkWidget *parent)
+{
+        GtkBuilder *builder;
+        GtkWidget *chooser;
+        CcFormatChooserPrivate *priv;
+        GError *error = NULL;
+
+        builder = gtk_builder_new ();
+        gtk_builder_add_from_resource (builder, "/org/gnome/control-center/region/format-chooser.ui", 
&error);
+        if (error) {
+                g_warning ("failed to load format chooser: %s", error->message);
+                g_error_free (error);
+                return NULL;
+        }
+
+        chooser = WID ("dialog");
+        priv = g_new0 (CcFormatChooserPrivate, 1);
+        g_object_set_data_full (G_OBJECT (chooser), "private", priv, cc_format_chooser_private_free);
+
+        priv->filter_entry = WID ("region-filter-entry");
+        priv->list = WID ("region-list");
+        priv->scrolledwindow = WID ("region-scrolledwindow");
+        priv->more_item = more_widget_new ();
+        priv->no_results = no_results_widget_new ();
+
+        priv->full_date = WID ("full-date-format");
+        priv->medium_date = WID ("medium-date-format");
+        priv->short_date = WID ("short-date-format");
+        priv->time = WID ("time-format");
+        priv->number = WID ("number-format");
+        priv->measurement = WID ("measurement-format");
+        priv->paper = WID ("paper-format");
+
+        egg_list_box_set_adjustment (EGG_LIST_BOX (priv->list),
+                                     gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW 
(priv->scrolledwindow)));
+
+        egg_list_box_set_sort_func (EGG_LIST_BOX (priv->list),
+                                    sort_regions, chooser, NULL);
+        egg_list_box_set_filter_func (EGG_LIST_BOX (priv->list),
+                                      region_visible, chooser, NULL);
+        egg_list_box_set_selection_mode (EGG_LIST_BOX (priv->list),
+                                         GTK_SELECTION_NONE);
+
+        add_all_regions (GTK_DIALOG (chooser));
+
+        g_signal_connect_swapped (priv->filter_entry, "changed",
+                                  G_CALLBACK (egg_list_box_refilter),
+                                  priv->list);
+
+        g_signal_connect (priv->list, "child-activated",
+                          G_CALLBACK (child_activated), chooser);
+
+        g_signal_connect_after (priv->list, "refilter",
+                                G_CALLBACK (end_refilter), chooser);
+
+        egg_list_box_refilter (EGG_LIST_BOX (priv->list));
+
+        gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (parent));
+
+        return chooser;
+}
+
+void
+cc_format_chooser_clear_filter (GtkWidget *chooser)
+{
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+
+        gtk_entry_set_text (GTK_ENTRY (priv->filter_entry), "");
+}
+
+const gchar *
+cc_format_chooser_get_region (GtkWidget *chooser)
+{
+        CcFormatChooserPrivate *priv = GET_PRIVATE (chooser);
+
+        return priv->region;
+}
+
+void
+cc_format_chooser_set_region (GtkWidget   *chooser,
+                              const gchar *region)
+{
+        set_locale_id (GTK_DIALOG (chooser), region);
+}
diff --git a/panels/region/cc-format-chooser.h b/panels/region/cc-format-chooser.h
new file mode 100644
index 0000000..77152a7
--- /dev/null
+++ b/panels/region/cc-format-chooser.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ *     Matthias Clasen
+ */
+
+#ifndef __CC_FORMAT_CHOOSER_H__
+#define __CC_FORMAT_CHOOSER_H__
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GtkWidget   *cc_format_chooser_new          (GtkWidget   *parent);
+void         cc_format_chooser_clear_filter (GtkWidget   *chooser);
+const gchar *cc_format_chooser_get_region   (GtkWidget   *chooser);
+void         cc_format_chooser_set_region   (GtkWidget   *chooser,
+                                             const gchar *region);
+
+G_END_DECLS
+
+#endif /* __CC_FORMAT_CHOOSER_H__ */
diff --git a/panels/region/cc-ibus-utils.c b/panels/region/cc-ibus-utils.c
new file mode 100644
index 0000000..54f9fb7
--- /dev/null
+++ b/panels/region/cc-ibus-utils.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_IBUS
+#include "cc-ibus-utils.h"
+
+gchar *
+engine_get_display_name (IBusEngineDesc *engine_desc)
+{
+        const gchar *name;
+        const gchar *language_code;
+        const gchar *language;
+        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);
+        display_name = g_strdup_printf ("%s (%s)", language, name);
+
+        return display_name;
+}
+
+#endif /* HAVE_IBUS */
diff --git a/panels/region/cc-ibus-utils.h b/panels/region/cc-ibus-utils.h
new file mode 100644
index 0000000..12f2545
--- /dev/null
+++ b/panels/region/cc-ibus-utils.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __CC_IBUS_UTILS_H__
+#define __CC_IBUS_UTILS_H__
+
+#include <ibus.h>
+
+G_BEGIN_DECLS
+
+gchar *engine_get_display_name (IBusEngineDesc *engine_desc);
+
+G_END_DECLS
+
+#endif /* __CC_IBUS_UTILS_H__ */
diff --git a/panels/region/cc-input-chooser.c b/panels/region/cc-input-chooser.c
new file mode 100644
index 0000000..0490758
--- /dev/null
+++ b/panels/region/cc-input-chooser.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2013 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include <config.h>
+#include <glib/gi18n.h>
+
+#include "cc-input-chooser.h"
+
+#ifdef HAVE_IBUS
+#include <ibus.h>
+#include "cc-ibus-utils.h"
+#endif
+
+#define INPUT_SOURCE_TYPE_XKB "xkb"
+#define INPUT_SOURCE_TYPE_IBUS "ibus"
+
+#define WID(name) ((GtkWidget *) gtk_builder_get_object (builder, name))
+
+enum {
+        NAME_COLUMN,
+        TYPE_COLUMN,
+        ID_COLUMN,
+        SETUP_COLUMN,
+        N_COLUMNS
+};
+
+static void
+filter_clear (GtkEntry             *entry,
+              GtkEntryIconPosition  icon_pos,
+              GdkEvent             *event,
+              gpointer              user_data)
+{
+  gtk_entry_set_text (entry, "");
+}
+
+static gchar **search_pattern_list;
+
+static void
+filter_changed (GtkBuilder *builder)
+{
+  GtkTreeModelFilter *filtered_model;
+  GtkTreeView *tree_view;
+  GtkTreeSelection *selection;
+  GtkTreeIter selected_iter;
+  GtkWidget *filter_entry;
+  const gchar *pattern;
+  gchar *upattern;
+
+  filter_entry = WID ("input_source_filter");
+  pattern = gtk_entry_get_text (GTK_ENTRY (filter_entry));
+  upattern = g_utf8_strup (pattern, -1);
+  if (!g_strcmp0 (pattern, ""))
+    g_object_set (G_OBJECT (filter_entry),
+                  "secondary-icon-name", "edit-find-symbolic",
+                  "secondary-icon-activatable", FALSE,
+                  "secondary-icon-sensitive", FALSE,
+                  NULL);
+  else
+    g_object_set (G_OBJECT (filter_entry),
+                  "secondary-icon-name", "edit-clear-symbolic",
+                  "secondary-icon-activatable", TRUE,
+                  "secondary-icon-sensitive", TRUE,
+                  NULL);
+
+  if (search_pattern_list != NULL)
+    g_strfreev (search_pattern_list);
+
+  search_pattern_list = g_strsplit (upattern, " ", -1);
+  g_free (upattern);
+  filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model"));
+  gtk_tree_model_filter_refilter (filtered_model);
+
+  tree_view = GTK_TREE_VIEW (WID ("filtered_input_source_list"));
+  selection = gtk_tree_view_get_selection (tree_view);
+  if (gtk_tree_selection_get_selected (selection, NULL, &selected_iter))
+    {
+      GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filtered_model),
+                                                   &selected_iter);
+      gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
+      gtk_tree_path_free (path);
+    }
+  else
+    {
+      GtkTreeIter iter;
+      if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter))
+        gtk_tree_selection_select_iter (selection, &iter);
+    }
+}
+
+static void
+selection_changed (GtkTreeSelection *selection,
+                   GtkBuilder       *builder)
+{
+  gtk_widget_set_sensitive (WID ("ok-button"),
+                            gtk_tree_selection_get_selected (selection, NULL, NULL));
+}
+
+static void
+row_activated (GtkTreeView       *tree_view,
+               GtkTreePath       *path,
+               GtkTreeViewColumn *column,
+               GtkBuilder        *builder)
+{
+  GtkWidget *add_button;
+  GtkWidget *dialog;
+
+  add_button = WID ("ok-button");
+  dialog = WID ("input_source_chooser");
+  if (gtk_widget_is_sensitive (add_button))
+    gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+}
+
+static void
+entry_activated (GtkBuilder *builder,
+                 gpointer    data)
+{
+  row_activated (NULL, NULL, NULL, builder);
+}
+
+static gboolean
+filter_func (GtkTreeModel *model,
+             GtkTreeIter  *iter,
+             gpointer      data)
+{
+  gchar *name = NULL;
+  gchar **pattern;
+  gboolean rv = TRUE;
+
+  if (search_pattern_list == NULL || search_pattern_list[0] == NULL)
+    return TRUE;
+
+  gtk_tree_model_get (model, iter,
+                      NAME_COLUMN, &name,
+                      -1);
+
+  pattern = search_pattern_list;
+  do {
+    gboolean is_pattern_found = FALSE;
+    gchar *udesc = g_utf8_strup (name, -1);
+    if (udesc != NULL && g_strstr_len (udesc, -1, *pattern))
+      {
+        is_pattern_found = TRUE;
+      }
+    g_free (udesc);
+
+    if (!is_pattern_found)
+      {
+        rv = FALSE;
+        break;
+      }
+
+  } while (*++pattern != NULL);
+  g_free (name);
+
+  return rv;
+}
+
+static void
+populate_model (GtkListStore *store,
+                GnomeXkbInfo *xkb_info,
+                GHashTable   *ibus_engines)
+{
+  GtkTreeIter iter;
+  const gchar *name;
+  GList *sources, *tmp;
+
+  sources = gnome_xkb_info_get_all_layouts (xkb_info);
+  for (tmp = sources; tmp; tmp = tmp->next)
+    {
+      gnome_xkb_info_get_layout_info (xkb_info, (const gchar *)tmp->data,
+                                      &name, NULL, NULL, NULL);
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter,
+                          NAME_COLUMN, name,
+                          TYPE_COLUMN, INPUT_SOURCE_TYPE_XKB,
+                          ID_COLUMN, tmp->data,
+                          -1);
+    }
+  g_list_free (sources);
+
+#ifdef HAVE_IBUS
+  if (ibus_engines)
+    {
+      gchar *display_name;
+
+      sources = g_hash_table_get_keys (ibus_engines);
+      for (tmp = sources; tmp; tmp = tmp->next)
+        {
+          display_name = engine_get_display_name (g_hash_table_lookup (ibus_engines, tmp->data));
+          gtk_list_store_append (store, &iter);
+          gtk_list_store_set (store, &iter,
+                              NAME_COLUMN, display_name,
+                              TYPE_COLUMN, INPUT_SOURCE_TYPE_IBUS,
+                              ID_COLUMN, tmp->data,
+                              -1);
+          g_free (display_name);
+        }
+      g_list_free (sources);
+    }
+#endif
+}
+
+
+GtkWidget *
+cc_input_chooser_new (GtkWindow    *main_window,
+                      GnomeXkbInfo *xkb_info,
+                      GHashTable   *ibus_engines)
+{
+  GtkBuilder *builder;
+  GtkWidget *chooser;
+  GtkWidget *filtered_list;
+  GtkWidget *filter_entry;
+  GtkTreeViewColumn *visible_column;
+  GtkTreeSelection *selection;
+  GtkListStore *model;
+  GtkTreeModelFilter *filtered_model;
+  GtkTreeIter iter;
+
+  builder = gtk_builder_new ();
+  gtk_builder_add_from_resource (builder,
+                                 "/org/gnome/control-center/region/gnome-region-panel-input-chooser.ui",
+                                 NULL);
+  chooser = WID ("input_source_chooser");
+  g_object_set_data_full (G_OBJECT (chooser), "builder", builder, g_object_unref);
+
+  filtered_list = WID ("filtered_input_source_list");
+  filter_entry = WID ("input_source_filter");
+
+  g_object_set_data (G_OBJECT (chooser),
+                     "filtered_input_source_list", filtered_list);
+  visible_column =
+    gtk_tree_view_column_new_with_attributes ("Input Sources",
+                                              gtk_cell_renderer_text_new (),
+                                              "text", NAME_COLUMN,
+                                              NULL);
+
+  gtk_window_set_transient_for (GTK_WINDOW (chooser), main_window);
+
+  gtk_tree_view_append_column (GTK_TREE_VIEW (filtered_list),
+                               visible_column);
+  /* We handle searching ourselves, thank you. */
+  gtk_tree_view_set_enable_search (GTK_TREE_VIEW (filtered_list), FALSE);
+  gtk_tree_view_set_search_column (GTK_TREE_VIEW (filtered_list), -1);
+
+  g_signal_connect_swapped (G_OBJECT (filter_entry), "activate",
+                            G_CALLBACK (entry_activated), builder);
+  g_signal_connect_swapped (G_OBJECT (filter_entry), "notify::text",
+                            G_CALLBACK (filter_changed), builder);
+
+  g_signal_connect (G_OBJECT (filter_entry), "icon-release",
+                    G_CALLBACK (filter_clear), NULL);
+
+  filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model"));
+  model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model"));
+
+  g_object_set_data_full (G_OBJECT (chooser), "xkb-info", g_object_ref (xkb_info), g_object_unref);
+  g_object_set_data_full (G_OBJECT (chooser), "ibus-engines", g_hash_table_ref (ibus_engines), 
(GDestroyNotify)g_hash_table_unref);
+
+  populate_model (model, xkb_info, ibus_engines);
+
+  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
+                                        NAME_COLUMN, GTK_SORT_ASCENDING);
+  gtk_tree_model_filter_set_visible_func (filtered_model,
+                                          filter_func,
+                                          NULL, NULL);
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (filtered_list));
+
+  g_signal_connect (G_OBJECT (selection), "changed",
+                    G_CALLBACK (selection_changed), builder);
+
+  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter))
+    gtk_tree_selection_select_iter (selection, &iter);
+
+  g_signal_connect (G_OBJECT (filtered_list), "row-activated",
+                    G_CALLBACK (row_activated), builder);
+
+  gtk_widget_grab_focus (filter_entry);
+
+  gtk_widget_show (chooser);
+
+  return chooser;
+}
+
+gboolean
+cc_input_chooser_get_selected (GtkWidget  *chooser,
+                               gchar     **type,
+                               gchar     **id,
+                               gchar     **name)
+{
+  GtkWidget *tv;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkTreeSelection *selection;
+
+  tv = g_object_get_data (G_OBJECT (chooser), "filtered_input_source_list");
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      gtk_tree_model_get (model, &iter,
+                          TYPE_COLUMN, type,
+                          ID_COLUMN, id,
+                          NAME_COLUMN, name,
+                          -1);
+      return TRUE;
+    }
+
+  return FALSE;
+}
diff --git a/panels/region/cc-input-chooser.h b/panels/region/cc-input-chooser.h
new file mode 100644
index 0000000..394db82
--- /dev/null
+++ b/panels/region/cc-input-chooser.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __CC_INPUT_CHOOSER_H__
+#define __CC_INPUT_CHOOSER_H__
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-xkb-info.h>
+
+
+G_BEGIN_DECLS
+
+GtkWidget   *cc_input_chooser_new          (GtkWindow    *parent,
+                                            GnomeXkbInfo *xkb_info,
+                                            GHashTable   *ibus_engines);
+gboolean     cc_input_chooser_get_selected (GtkWidget    *chooser,
+                                            gchar       **type,
+                                            gchar       **id,
+                                            gchar       **name);
+
+G_END_DECLS
+
+#endif /* __CC_INPUT_CHOOSER_H__ */
diff --git a/panels/region/cc-input-options.c b/panels/region/cc-input-options.c
new file mode 100644
index 0000000..51c54eb
--- /dev/null
+++ b/panels/region/cc-input-options.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2013 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ *     Matthias Clasen
+ */
+
+#define _GNU_SOURCE
+#include <config.h>
+#include "cc-input-options.h"
+
+#include <glib/gi18n.h>
+
+
+typedef struct {
+        GtkWidget *dialog;
+        GtkWidget *same_source;
+        GtkWidget *per_window_source;
+        GtkWidget *previous_source;
+        GtkWidget *next_source;
+        GtkWidget *alt_next_source;
+        GSettings *settings;
+} CcInputOptionsPrivate;
+
+#define GET_PRIVATE(options) ((CcInputOptionsPrivate *) g_object_get_data (G_OBJECT (options), "private"))
+
+static void
+cc_input_options_private_free (gpointer data)
+{
+        CcInputOptionsPrivate *priv = data;
+
+        g_clear_object (&priv->settings);
+        g_free (priv);
+}
+
+static void
+update_shortcut_label (GtkWidget   *widget,
+                       const gchar *value)
+{
+        gchar *text;
+        guint accel_key, *keycode;
+        GdkModifierType mods;
+
+        if (value == NULL || *value == '\0') {
+                gtk_widget_hide (widget);
+                return;
+        }
+
+        gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods);
+        if (accel_key == 0 && keycode == NULL && mods == 0) {
+                g_warning ("Failed to parse keyboard shortcut: '%s'", value);
+                gtk_widget_hide (widget);
+                return;
+        }
+
+        text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, 
mods);
+        g_free (keycode);
+        gtk_label_set_text (GTK_LABEL (widget), text);
+        g_free (text);
+}
+
+static struct
+{
+  const gchar *value;
+  const gchar *description;
+} input_switcher_options[] =
+{
+  { "off", N_("Disabled") },
+  { "shift-l", N_("Left Shift") },
+  { "alt-l", N_("Left Alt") },
+  { "ctrl-l", N_("Left Ctrl") },
+  { "shift-r", N_("Right Shift") },
+  { "alt-r", N_("Right Alt") },
+  { "ctrl-r", N_("Right Ctrl") },
+  { "alt-shift-l", N_("Left Alt+Shift") },
+  { "alt-shift-r", N_("Right Alt+Shift") },
+  { "ctrl-shift-l", N_("Left Ctrl+Shift") },
+  { "ctrl-shift-r", N_("Right Ctrl+Shift") },
+  { "shift-l-shift-r", N_("Left+Right Shift") },
+  { "alt-l-alt-r", N_("Left+Right Alt") },
+  { "ctrl-l-ctrl-r", N_("Left+Right Ctrl") },
+  { "alt-shift", N_("Alt+Shift") },
+  { "ctrl-shift", N_("Ctrl+Shift") },
+  { "alt-ctrl", N_("Alt+Ctrl") },
+  { "caps", N_("Caps") },
+  { "shift-caps", N_("Shift+Caps") },
+  { "alt-caps", N_("Alt+Caps") },
+  { "ctrl-caps", N_("Ctrl+Caps") },
+  { NULL, NULL }
+};
+
+static void
+update_shortcuts (GtkWidget *options)
+{
+        CcInputOptionsPrivate *priv = GET_PRIVATE (options);
+        gchar **previous;
+        gchar **next;
+        gchar *previous_shortcut;
+        GSettings *settings;
+        gchar *s;
+        gint i;
+
+        settings = g_settings_new ("org.gnome.desktop.wm.keybindings");
+
+        previous = g_settings_get_strv (settings, "switch-input-source-backward");
+        next = g_settings_get_strv (settings, "switch-input-source");
+
+        previous_shortcut = g_strdup (previous[0]);
+        if (!previous_shortcut && next[0]) {
+                previous_shortcut = g_strconcat ("<Shift>", next[0], NULL);
+        }
+
+        update_shortcut_label (priv->previous_source, previous_shortcut);
+        update_shortcut_label (priv->next_source, next[0]);
+
+        g_free (previous_shortcut);
+
+        g_strfreev (previous);
+        g_strfreev (next);
+
+        g_object_unref (settings);
+
+        settings = g_settings_new ("org.gnome.settings-daemon.peripherals.keyboard");
+        s = g_settings_get_string (settings, "input-sources-switcher");
+
+        if (strcmp (s, "off") == 0) {
+                gtk_widget_hide (priv->alt_next_source);
+        } else {
+                for (i = 0; input_switcher_options[i].value; i++) {
+                        if (strcmp (s, input_switcher_options[i].value) == 0) {
+                                gtk_label_set_text (GTK_LABEL (priv->alt_next_source), 
_(input_switcher_options[i].description));
+                                break;
+                        }
+                }
+        }
+        g_free (s);
+        g_object_unref (settings);
+}
+
+#define WID(name) ((GtkWidget *) gtk_builder_get_object (builder, name))
+
+GtkWidget *
+cc_input_options_new (GtkWidget *parent)
+{
+        GtkBuilder *builder;
+        GtkWidget *options;
+        CcInputOptionsPrivate *priv;
+        GError *error = NULL;
+
+        builder = gtk_builder_new ();
+        gtk_builder_add_from_resource (builder, "/org/gnome/control-center/region/input-options.ui", &error);
+        if (error) {
+                g_warning ("failed to load input options: %s", error->message);
+                g_error_free (error);
+                return NULL;
+        }
+
+        options = WID ("dialog");
+        priv = g_new0 (CcInputOptionsPrivate, 1);
+        g_object_set_data_full (G_OBJECT (options), "private", priv, cc_input_options_private_free);
+
+        priv->same_source = WID ("same-source");
+        priv->per_window_source = WID ("per-window-source");
+        priv->previous_source = WID ("previous-source");
+        priv->next_source = WID ("next-source");
+        priv->alt_next_source = WID ("alt-next-source");
+
+        g_object_bind_property (priv->previous_source, "visible",
+                                WID ("previous-source-label"), "visible",
+                                G_BINDING_DEFAULT);
+        g_object_bind_property (priv->next_source, "visible",
+                                WID ("next-source-label"), "visible",
+                                G_BINDING_DEFAULT);
+        g_object_bind_property (priv->alt_next_source, "visible",
+                                WID ("alt-next-source-label"), "visible",
+                                G_BINDING_DEFAULT);
+
+        priv->settings = g_settings_new ("org.gnome.desktop.input-sources");
+        g_settings_bind (priv->settings, "per-window",
+                         priv->per_window_source, "active",
+                         G_SETTINGS_BIND_DEFAULT);
+
+        update_shortcuts (options);
+
+        gtk_window_set_transient_for (GTK_WINDOW (options), GTK_WINDOW (parent));
+
+        return options;
+}
diff --git a/panels/region/cc-input-options.h b/panels/region/cc-input-options.h
new file mode 100644
index 0000000..5d7c4f2
--- /dev/null
+++ b/panels/region/cc-input-options.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by:
+ *     Matthias Clasen
+ */
+
+#ifndef __CC_INPUT_OPTIONS_H__
+#define __CC_INPUT_OPTIONS_H__
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *cc_input_options_new (GtkWidget *parent);
+
+G_END_DECLS
+
+#endif /* __CC_FORMAT_CHOOSER_H__ */
diff --git a/panels/region/cc-region-panel.c b/panels/region/cc-region-panel.c
index f271208..f390386 100644
--- a/panels/region/cc-region-panel.c
+++ b/panels/region/cc-region-panel.c
@@ -21,42 +21,108 @@
 
 #include <config.h>
 #include <glib/gi18n.h>
+#include <gio/gdesktopappinfo.h>
 
 #include "cc-region-panel.h"
 #include "cc-region-resources.h"
+#include "cc-language-chooser.h"
+#include "cc-format-chooser.h"
+#include "cc-input-chooser.h"
+#include "cc-input-options.h"
 
 #include <gtk/gtk.h>
 
-#include "gnome-region-panel-input.h"
-#include "gnome-region-panel-lang.h"
-#include "gnome-region-panel-formats.h"
-#include "gnome-region-panel-system.h"
+#include "cc-common-language.h"
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-languages.h>
+#include <libgnome-desktop/gnome-xkb-info.h>
+
+#ifdef HAVE_IBUS
+#include <ibus.h>
+#include "supported-ibus-engines.h"
+#include "cc-ibus-utils.h"
+#endif
 
 #include "egg-list-box/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 GNOME_SYSTEM_LOCALE_DIR "org.gnome.system.locale"
+#define KEY_REGION "region"
+
+#define INPUT_SOURCE_TYPE_XKB "xkb"
+#define INPUT_SOURCE_TYPE_IBUS "ibus"
+
+
+static gboolean
+strv_contains (const gchar * const *strv,
+               const gchar         *str)
+{
+  const gchar * const *p = strv;
+  for (p = strv; *p; p++)
+    if (g_strcmp0 (*p, str) == 0)
+      return TRUE;
+
+  return FALSE;
+}
+
 CC_PANEL_REGISTER (CcRegionPanel, cc_region_panel)
 
+#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s))
+
 #define REGION_PANEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_REGION_PANEL, 
CcRegionPanelPrivate))
 
 struct _CcRegionPanelPrivate {
        GtkBuilder *builder;
 
         GtkWidget *login_button;
+
         GtkWidget *language_row;
+        GtkWidget *language_label;
         GtkWidget *formats_row;
+        GtkWidget *formats_label;
+
+        GDBusProxy *user;
+        GSettings  *locale_settings;
+
+        gchar *language;
+        gchar *region;
+
         GtkWidget *options_button;
-        GtkWidget *input_source_list;
+        GtkWidget *input_list;
+        GtkWidget *add_input;
+        GtkWidget *remove_input;
+        GtkWidget *show_config;
+        GtkWidget *show_layout;
+
+        GSettings *input_settings;
+        GnomeXkbInfo *xkb_info;
+#ifdef HAVE_IBUS
+        IBusBus *ibus;
+        GHashTable *ibus_engines;
+        GCancellable *ibus_cancellable;
+#endif
 };
 
 static void
-cc_region_panel_finalize (GObject * object)
+cc_region_panel_finalize (GObject *object)
 {
-       CcRegionPanel *panel;
-
-       panel = CC_REGION_PANEL (object);
+       CcRegionPanel *self = CC_REGION_PANEL (object);
+       CcRegionPanelPrivate *priv = self->priv;
 
-       if (panel->priv && panel->priv->builder)
-               g_object_unref (panel->priv->builder);
+        g_clear_object (&priv->builder);
+        g_clear_object (&priv->user);
+        g_clear_object (&priv->locale_settings);
+        g_clear_object (&priv->input_settings);
+        g_clear_object (&priv->xkb_info);
+        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);
 
        G_OBJECT_CLASS (cc_region_panel_parent_class)->finalize (object);
 }
@@ -65,20 +131,23 @@ static void
 cc_region_panel_constructed (GObject *object)
 {
         CcRegionPanel *self = CC_REGION_PANEL (object);
+       CcRegionPanelPrivate *priv = self->priv;
 
         G_OBJECT_CLASS (cc_region_panel_parent_class)->constructed (object);
 
-        self->priv->login_button = gtk_button_new_with_label (_("Login Screen"));
+#if 0
+        priv->login_button = gtk_button_new_with_label (_("Login Screen"));
 
         cc_shell_embed_widget_in_header (cc_panel_get_shell (CC_PANEL (object)),
-                                         self->priv->login_button);
-        gtk_widget_show_all (self->priv->login_button);
+                                         priv->login_button);
+        gtk_widget_show_all (priv->login_button);
+#endif
 }
 
 static const char *
 cc_region_panel_get_help_uri (CcPanel *panel)
 {
-  return "help:gnome-help/prefs-language";
+        return "help:gnome-help/prefs-language";
 }
 
 static void
@@ -101,97 +170,300 @@ update_separator_func (GtkWidget **separator,
                        GtkWidget  *before,
                        gpointer    user_data)
 {
-  if (before == NULL)
-    return;
+        if (before == NULL)
+                return;
+
+        if (*separator == NULL) {
+                *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+                g_object_ref_sink (*separator);
+                gtk_widget_show (*separator);
+        }
+}
 
-  if (*separator == NULL)
-    {
-      *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-      g_object_ref_sink (*separator);
-      gtk_widget_show (*separator);
-    }
+static void
+update_language (CcRegionPanel *self,
+                 const gchar   *language)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        gchar *name;
+
+        g_free (priv->language);
+        priv->language = g_strdup (language);
+
+        name = gnome_get_language_from_name (language, language);
+        gtk_label_set_label (GTK_LABEL (priv->language_label), name);
+        g_free (name);
 }
 
 static void
-activate_input_child (CcRegionPanel *self, GtkWidget child)
+store_language (CcRegionPanel *self)
 {
+       CcRegionPanelPrivate *priv = self->priv;
+        g_dbus_proxy_call (priv->user,
+                           "SetLanguage",
+                           g_variant_new ("(s)", priv->language),
+                           0,
+                           G_MAXINT,
+                           NULL,
+                           NULL,
+                           NULL);
 }
 
 static void
-add_language_section (CcRegionPanel *self)
+language_response (GtkDialog     *chooser,
+                   gint           response_id,
+                   CcRegionPanel *self)
+{
+        const gchar *language;
+
+        language = cc_language_chooser_get_language (GTK_WIDGET (chooser));
+        update_language (self, language);
+        store_language (self);
+        gtk_widget_destroy (GTK_WIDGET (chooser));
+}
+
+static void
+format_response (GtkDialog *chooser,
+                 gint       response_id,
+                 CcRegionPanel *self)
 {
        CcRegionPanelPrivate *priv = self->priv;
-        GtkWidget *vbox;
-        GtkWidget *frame;
-        GtkWidget *widget;
-        GtkWidget *row;
-        GtkWidget *label;
+        const gchar *region;
 
-        vbox = GTK_WIDGET (gtk_builder_get_object (priv->builder, "vbox_region"));
+        region = cc_format_chooser_get_region (GTK_WIDGET (chooser));
+        g_settings_set_string (priv->locale_settings, KEY_REGION, region);
+        gtk_widget_destroy (GTK_WIDGET (chooser));
+}
+
+static void
+activate_language_child (CcRegionPanel *self, GtkWidget *child)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        GtkWidget *chooser;
+        GtkWidget *toplevel;
+
+        toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+        if (child == priv->language_row) {
+                chooser = cc_language_chooser_new (toplevel);
+                cc_language_chooser_set_language (chooser, priv->language);
+                g_signal_connect (chooser, "response",
+                                  G_CALLBACK (language_response), self);
+                gtk_window_present (GTK_WINDOW (chooser));
+        } else if (child == priv->formats_row) {
+                chooser = cc_format_chooser_new (toplevel);
+                cc_format_chooser_set_region (chooser, priv->region);
+                g_signal_connect (chooser, "response",
+                                  G_CALLBACK (format_response), self);
+                gtk_window_present (GTK_WINDOW (chooser));
+        }
+}
+
+static void
+set_initial_language (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        GVariant *p;
+        gchar *lang;
+
+        p = g_dbus_proxy_get_cached_property (priv->user, "Language");
+        lang = g_variant_dup_string (p, NULL);
+        update_language (self, lang);
+        g_free (lang);
+        g_variant_unref (p);
+}
+
+static void
+update_region (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        gchar *name;
+
+        g_free (priv->region);
+        priv->region = g_settings_get_string (priv->locale_settings, KEY_REGION);
+        name = gnome_get_region_from_name (priv->region, priv->region);
+        gtk_label_set_label (GTK_LABEL (priv->formats_label), name);
+        g_free (name);
+}
 
-        widget = GTK_WIDGET (egg_list_box_new ());
+static void
+setup_language_section (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        GtkWidget *widget;
+        gchar *path;
+        GError *error = NULL;
+
+        path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", getuid ());
+        priv->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 (priv->user == NULL) {
+                g_warning ("Failed to get proxy for user '%s': %s",
+                           path, error->message);
+                g_error_free (error);
+                g_free (path);
+                return;
+        }
+        g_free (path);
+
+        priv->locale_settings = g_settings_new (GNOME_SYSTEM_LOCALE_DIR);
+        g_signal_connect_swapped (priv->locale_settings, "changed::" KEY_REGION,
+                                  G_CALLBACK (update_region), self);
+
+        priv->language_row = WID ("language_row");
+        priv->language_label = WID ("language_label");
+        priv->formats_row = WID ("formats_row");
+        priv->formats_label = WID ("formats_label");
+
+        widget = WID ("language_list");
         egg_list_box_set_selection_mode (EGG_LIST_BOX (widget),
                                          GTK_SELECTION_NONE);
         egg_list_box_set_separator_funcs (EGG_LIST_BOX (widget),
                                           update_separator_func,
                                           NULL, NULL);
         g_signal_connect_swapped (widget, "child-activated",
-                                  G_CALLBACK (activate_input_child), self);
+                                  G_CALLBACK (activate_language_child), self);
 
+        set_initial_language (self);
+        update_region (self);
+}
 
-        frame = gtk_frame_new (NULL);
-        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
-        gtk_widget_set_margin_left (frame, 134);
-        gtk_widget_set_margin_right (frame, 134);
-        gtk_widget_set_margin_bottom (frame, 22);
+#ifdef HAVE_IBUS
+static void
+update_ibus_active_sources (CcRegionPanel *self)
+{
+        CcRegionPanelPrivate *priv = self->priv;
+        GList *rows, *l;
+        GtkWidget *row;
+        const gchar *type;
+        const gchar *id;
+        IBusEngineDesc *engine_desc;
+        gchar *display_name;
+        GtkWidget *label;
 
-        gtk_container_add (GTK_CONTAINER (frame), widget);
-        gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
+        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);
+}
 
-        priv->language_row = row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-        gtk_container_add (GTK_CONTAINER (widget), priv->language_row);
-        label = gtk_label_new (_("Language"));
-        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);
+static void
+fetch_ibus_engines_result (GObject       *object,
+                           GAsyncResult  *result,
+                           CcRegionPanel *self)
+{
+        CcRegionPanelPrivate *priv = self->priv;
+        gboolean show_all_sources;
+        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;
+        }
+
+        show_all_sources = g_settings_get_boolean (priv->input_settings, "show-all-sources");
+
+        /* 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 (show_all_sources || strv_contains (supported_ibus_engines, engine_id))
+                        g_hash_table_replace (priv->ibus_engines, (gpointer)engine_id, engine);
+                else
+                        g_object_unref (engine);
+        }
+        g_list_free (list);
+
+        update_ibus_active_sources (self);
+}
 
-        label = gtk_label_new ("English (United Kingdom)");
-        gtk_misc_set_alignment (GTK_MISC (label), 1, 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, FALSE, TRUE, 0);
+static void
+fetch_ibus_engines (CcRegionPanel *self)
+{
+        CcRegionPanelPrivate *priv = self->priv;
 
-        priv->formats_row = row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-        gtk_container_add (GTK_CONTAINER (widget), priv->formats_row);
-        label = gtk_label_new (_("Formats"));
-        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);
+        priv->ibus_cancellable = g_cancellable_new ();
 
-        label = gtk_label_new ("United Kingdom");
-        gtk_misc_set_alignment (GTK_MISC (label), 1, 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, FALSE, TRUE, 0);
+        ibus_bus_list_engines_async (priv->ibus,
+                                     -1,
+                                     priv->ibus_cancellable,
+                                     (GAsyncReadyCallback)fetch_ibus_engines_result,
+                                     self);
 
-        gtk_widget_show_all (frame);
+  /* 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
-add_keyboard_layout_row (CcRegionPanel *self, const gchar *name)
+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 GtkWidget *
+add_input_row (CcRegionPanel   *self,
+               const gchar     *type,
+               const gchar     *id,
+               const gchar     *name,
+               GDesktopAppInfo *app_info)
 {
         GtkWidget *row;
         GtkWidget *label;
+        GtkWidget *image;
 
         row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
         label = gtk_label_new (name);
@@ -201,92 +473,478 @@ add_keyboard_layout_row (CcRegionPanel *self, const gchar *name)
         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_box_pack_start (GTK_BOX (row), image, FALSE, TRUE, 0);
+        }
+
         gtk_widget_show_all (row);
-        gtk_container_add (GTK_CONTAINER (self->priv->input_source_list), row);
+        gtk_container_add (GTK_CONTAINER (self->priv->input_list), 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);
+        }
+
+        return row;
 }
 
 static void
-add_input_method_row (CcRegionPanel *self, const gchar *name)
+populate_with_active_sources (CcRegionPanel *self)
 {
-        GtkWidget *row;
-        GtkWidget *label;
-        GtkWidget *image;
+        CcRegionPanelPrivate *priv = self->priv;
+        GVariant *sources;
+        GVariantIter iter;
+        const gchar *type;
+        const gchar *id;
+        const gchar *name;
+        gchar *display_name;
+        GDesktopAppInfo *app_info;
+
+        sources = g_settings_get_value (priv->input_settings, "sources");
+        g_variant_iter_init (&iter, sources);
+        while (g_variant_iter_next (&iter, "(&s&s)", &type, &id)) {
+                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);
+                                continue;
+                        }
+                        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);
+                        continue;
+                }
+
+                add_input_row (self, type, id, display_name ? display_name : id, app_info);
+                g_free (display_name);
+                g_clear_object (&app_info);
+        }
+        g_variant_unref (sources);
+}
 
-        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);
+static void
+container_remove_all (GtkContainer *container)
+{
+        GList *list, *l;
+        list = gtk_container_get_children (container);
+        for (l = list; l; l = l->next) {
+                gtk_container_remove (container, GTK_WIDGET (l->data));
+        }
+        g_list_free (list);
+}
 
-        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_box_pack_start (GTK_BOX (row), image, FALSE, TRUE, 0);
+static void
+select_by_id (GtkWidget   *row,
+              gpointer     data)
+{
+        const gchar *id = data;
+        const gchar *row_id;
 
-        gtk_widget_show_all (row);
-        gtk_container_add (GTK_CONTAINER (self->priv->input_source_list), row);
+        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 (CcRegionPanel *self,
+              const gchar   *id)
+{
+        gtk_container_foreach (GTK_CONTAINER (self->priv->input_list),
+                               select_by_id, (gpointer)id);
 }
 
 static void
-add_input_section (CcRegionPanel *self)
+input_sources_changed (GSettings     *settings,
+                       const gchar   *key,
+                       CcRegionPanel *self)
 {
        CcRegionPanelPrivate *priv = self->priv;
-        GtkWidget *vbox;
-        GtkWidget *box;
-        GtkWidget *widget;
-        GtkWidget *row;
-        GtkWidget *label;
-        GtkWidget *frame;
-        gchar *s;
+        GtkWidget *selected;
+        const gchar *id = NULL;
+
+        selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->input_list));
+        if (selected)
+                id = (const gchar *)g_object_get_data (G_OBJECT (selected), "id");
+        container_remove_all (GTK_CONTAINER (priv->input_list));
+        populate_with_active_sources (self);
+        if (id)
+                select_input (self, id);
+}
 
-        vbox = GTK_WIDGET (gtk_builder_get_object (priv->builder, "vbox_region"));
 
-        box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-        gtk_widget_set_margin_left (box, 134);
-        gtk_widget_set_margin_right (box, 134);
-        gtk_widget_set_margin_top (box, 0);
-        gtk_widget_set_margin_bottom (box, 22);
-        gtk_box_pack_start (GTK_BOX (vbox), box, TRUE, TRUE, 0);
-
-        s = g_strdup_printf ("<b>%s</b>", _("Input Sources"));
-        label = gtk_label_new (s);
-        g_free (s);
-        gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-        gtk_widget_set_margin_left (label, 6);
-        gtk_widget_set_margin_right (label, 6);
-        gtk_widget_set_margin_bottom (label, 6);
-        row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-        gtk_box_pack_start (GTK_BOX (row), label, TRUE, TRUE, 0);
+static void
+update_button_sensitivity (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        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_sensitive (priv->remove_input, FALSE);
+                gtk_widget_set_sensitive (priv->show_config, 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_sensitive (priv->show_config, app_info != NULL);
+                gtk_widget_set_sensitive (priv->show_layout, TRUE);
+                gtk_widget_set_sensitive (priv->remove_input, multiple_sources);
+        }
+        gtk_widget_set_visible (priv->options_button, multiple_sources);
+}
 
-        self->priv->options_button = gtk_button_new_with_label (_("Options"));
-        gtk_widget_set_margin_bottom (label, 6);
-        gtk_box_pack_start (GTK_BOX (row), self->priv->options_button, FALSE, TRUE, 0);
-        gtk_box_pack_start (GTK_BOX (box), row, FALSE, TRUE, 0);
+static void
+update_configuration (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        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;
+
+        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);
+
+        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);
+}
 
-        priv->input_source_list = widget = GTK_WIDGET (egg_list_box_new ());
-        egg_list_box_set_selection_mode (EGG_LIST_BOX (widget),
+static void
+select_input_child (CcRegionPanel *self, GtkWidget *child)
+{
+        update_button_sensitivity (self);
+}
+
+static void
+chooser_response (GtkWidget *chooser, gint response_id, gpointer data)
+{
+       CcRegionPanel *self = data;
+       CcRegionPanelPrivate *priv = self->priv;
+        gchar *type;
+        gchar *id;
+        gchar *name;
+        GDesktopAppInfo *app_info = NULL;
+
+        if (cc_input_chooser_get_selected (chooser, &type, &id, &name)) {
+                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;
+                }
+                add_input_row (self, type, id, name, app_info);
+                g_free (id);
+                g_free (name);
+                g_clear_object (&app_info);
+
+                update_button_sensitivity (self);
+                update_configuration (self);
+        }
+
+        gtk_widget_destroy (chooser);
+}
+
+static void
+add_input (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        GtkWidget *chooser;
+        GtkWidget *toplevel;
+
+        toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+        chooser = cc_input_chooser_new (GTK_WINDOW (toplevel),
+                                        priv->xkb_info,
+                                        priv->ibus_engines);
+        g_signal_connect (chooser, "response",
+                          G_CALLBACK (chooser_response), self);
+}
+
+static GtkWidget *
+find_sibling (GtkContainer *container, GtkWidget *child)
+{
+        GList *list, *c;
+        GList *l;
+        GtkWidget *sibling;
+
+        list = gtk_container_get_children (container);
+        c = g_list_find (list, child);
+
+        for (l = c->next; l; l = l->next) {
+                sibling = l->data;
+                if (gtk_widget_get_visible (sibling) && gtk_widget_get_child_visible (sibling))
+                        goto out;
+        }
+
+        for (l = c->prev; l; l = l->prev) {
+                sibling = l->data;
+                if (gtk_widget_get_visible (sibling) && gtk_widget_get_child_visible (sibling))
+                        goto out;
+        }
+
+        sibling = NULL;
+
+out:
+        g_list_free (list);
+
+        return sibling;
+}
+
+static void
+remove_selected_input (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        GtkWidget *selected;
+        GtkWidget *sibling;
+
+        selected = egg_list_box_get_selected_child (EGG_LIST_BOX (priv->input_list));
+        if (selected == NULL)
+                return;
+
+        sibling = find_sibling (GTK_CONTAINER (priv->input_list), selected);
+        gtk_container_remove (GTK_CONTAINER (priv->input_list), selected);
+        egg_list_box_select_child (EGG_LIST_BOX (priv->input_list), sibling);
+
+        update_button_sensitivity (self);
+        update_configuration (self);
+}
+
+static void
+show_selected_settings (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        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 (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+        GtkWidget *selected;
+        const gchar *type;
+        const gchar *id;
+        const gchar *layout;
+        const gchar *variant;
+        gchar *commandline;
+
+        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);
+
+        g_spawn_command_line_async (commandline, NULL);
+        g_free (commandline);
+}
+
+static void
+options_response (GtkDialog     *options,
+                  gint           response_id,
+                  CcRegionPanel *self)
+{
+        gtk_widget_destroy (GTK_WIDGET (options));
+}
+
+
+static void
+show_input_options (CcRegionPanel *self)
+{
+        GtkWidget *toplevel;
+        GtkWidget *options;
+
+        toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+        options = cc_input_options_new (toplevel);
+        g_signal_connect (options, "response",
+                          G_CALLBACK (options_response), self);
+        gtk_window_present (GTK_WINDOW (options));
+}
+
+static void
+setup_input_section (CcRegionPanel *self)
+{
+       CcRegionPanelPrivate *priv = self->priv;
+
+        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->options_button = WID ("input_options");
+        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");
+
+        g_signal_connect_swapped (priv->options_button, "clicked",
+                                  G_CALLBACK (show_input_options), self);
+        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);
+
+        egg_list_box_set_selection_mode (EGG_LIST_BOX (priv->input_list),
                                          GTK_SELECTION_SINGLE);
-        egg_list_box_set_separator_funcs (EGG_LIST_BOX (widget),
+        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 (select_input_child), self);
 
-        frame = gtk_frame_new (NULL);
-        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
-
-        gtk_container_add (GTK_CONTAINER (frame), widget);
-        gtk_box_pack_start (GTK_BOX (box), frame, FALSE, TRUE, 0);
+        g_signal_connect (priv->input_settings, "changed::" KEY_INPUT_SOURCES,
+                          G_CALLBACK (input_sources_changed), self);
 
-        add_keyboard_layout_row (self, _("English (UK)"));
-        add_input_method_row (self, _("Japanese (Anthy)"));
-        add_input_method_row (self, _("Chinese (Pinyin)"));
+        populate_with_active_sources (self);
 
-        gtk_widget_show_all (box);
+        update_button_sensitivity (self);
 }
 
 static void
@@ -310,8 +968,8 @@ cc_region_panel_init (CcRegionPanel *self)
                return;
        }
 
-        add_language_section (self);
-        add_input_section (self);
+        setup_language_section (self);
+        setup_input_section (self);
 
         vbox = GTK_WIDGET (gtk_builder_get_object (priv->builder, "vbox_region"));
        gtk_widget_reparent (vbox, GTK_WIDGET (self));
diff --git a/panels/region/format-chooser.ui b/panels/region/format-chooser.ui
new file mode 100644
index 0000000..3b3d598
--- /dev/null
+++ b/panels/region/format-chooser.ui
@@ -0,0 +1,344 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkDialog" id="dialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Formats</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="homogeneous">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="ok-button">
+                <property name="label" translatable="yes">_Done</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="box1">
+            <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="margin_top">6</property>
+            <property name="margin_bottom">6</property>
+            <property name="hexpand">True</property>
+            <property name="spacing">20</property>
+            <child>
+              <object class="GtkBox" id="box2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="vexpand">True</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkScrolledWindow" id="region-scrolledwindow">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="hscrollbar_policy">never</property>
+                    <property name="vscrollbar_policy">never</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkViewport" id="viewport1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <object class="EggListBox" id="region-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>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkSearchEntry" id="region-filter-entry">
+                    <property name="visible">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="can_focus">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</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="GtkGrid" id="grid1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">start</property>
+                <property name="valign">start</property>
+                <property name="margin_right">20</property>
+                <property name="hexpand">True</property>
+                <property name="row_spacing">6</property>
+                <property name="column_spacing">6</property>
+                <child>
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="margin_bottom">6</property>
+                    <property name="hexpand">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Preview</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">2</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">Dates</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="full-date-format">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label">Wednesday, January 23</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="medium-date-format">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label">23 January 2013</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">2</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="short-date-format">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label">23/1/13</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">3</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">Times</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">4</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="time-format">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label">11:31 AM</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">4</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">Numbers</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">5</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label6">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Measurement</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">6</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label7">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">Paper</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">7</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="number-format">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label">123,456,789.00</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">5</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="measurement-format">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label">Metric</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">6</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="paper-format">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label">A4</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">7</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">ok-button</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/panels/region/input-options.ui b/panels/region/input-options.ui
new file mode 100644
index 0000000..570b219
--- /dev/null
+++ b/panels/region/input-options.ui
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkDialog" id="dialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Input Source Options</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="ok-button">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="grid1">
+            <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="margin_top">6</property>
+            <property name="margin_bottom">6</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">6</property>
+            <child>
+              <object class="GtkRadioButton" id="same-source">
+                <property name="label" translatable="yes">Use the _same source for all windows</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="per-window-source">
+                <property name="label" translatable="yes">Allow _different sources for each window</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">same-source</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_top">6</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Keyboard Shortcuts</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">2</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="previous-source-label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">Switch to previous source</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">3</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="previous-source">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Super+Shift+Space</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">3</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="next-source-label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">Switch to next source</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">4</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="next-source">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Super+Space</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">4</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="margin_top">6</property>
+                <property name="label" translatable="yes">You can change these shortcuts in the keyboard 
settings</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">6</property>
+                <property name="width">2</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="alt-next-source-label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">Alternative switch to next source</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">5</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="alt-next-source">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Left+Right Alt</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">5</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-5">ok-button</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/panels/region/region.gresource.xml b/panels/region/region.gresource.xml
index 815ed36..8370c0a 100644
--- a/panels/region/region.gresource.xml
+++ b/panels/region/region.gresource.xml
@@ -1,8 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <gresources>
   <gresource prefix="/org/gnome/control-center/region">
-    <file preprocess="xml-stripblanks">gnome-region-panel.ui</file>
-    <file preprocess="xml-stripblanks">gnome-region-panel-input-chooser.ui</file>
     <file preprocess="xml-stripblanks">region.ui</file>
+    <file preprocess="xml-stripblanks">format-chooser.ui</file>
+    <file preprocess="xml-stripblanks">input-options.ui</file>
+    <file preprocess="xml-stripblanks">gnome-region-panel-input-chooser.ui</file>
   </gresource>
 </gresources>
diff --git a/panels/region/region.ui b/panels/region/region.ui
index 1c885d7..4ef26bd 100644
--- a/panels/region/region.ui
+++ b/panels/region/region.ui
@@ -5,13 +5,343 @@
     <property name="can_focus">False</property>
     <property name="resizable">False</property>
     <child>
-      <object class="GtkVBox" id="vbox_region">
+      <object class="GtkBox" id="vbox_region">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="border_width">12</property>
-        <property name="spacing">3</property>
+        <property name="orientation">vertical</property>
         <child>
-          <placeholder/>
+          <object class="GtkFrame" id="language_section">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">134</property>
+            <property name="margin_right">134</property>
+            <property name="margin_bottom">24</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="EggListBox" id="language_list">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <child>
+                  <object class="GtkBox" id="language_row">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkLabel" id="language_heading">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="margin_left">20</property>
+                        <property name="margin_right">20</property>
+                        <property name="margin_top">6</property>
+                        <property name="margin_bottom">6</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Language</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="language_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">1</property>
+                        <property name="margin_left">20</property>
+                        <property name="margin_right">20</property>
+                        <property name="margin_top">6</property>
+                        <property name="margin_bottom">6</property>
+                        <property name="label" translatable="yes">English (United Kingdom)</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkBox" id="formats_row">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkLabel" id="formats_heading">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="margin_left">20</property>
+                        <property name="margin_right">20</property>
+                        <property name="margin_top">6</property>
+                        <property name="margin_bottom">6</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Formats</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="formats_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">1</property>
+                        <property name="margin_left">20</property>
+                        <property name="margin_right">20</property>
+                        <property name="margin_top">6</property>
+                        <property name="margin_bottom">6</property>
+                        <property name="label" translatable="yes">United Kingdom</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label_item">
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="input_section">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">134</property>
+            <property name="margin_right">134</property>
+            <property name="margin_bottom">24</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">Input Sources</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="input_options">
+                    <property name="label" translatable="yes">Options</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</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="EggListBox" id="input_list">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</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>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
         </child>
       </object>
     </child>
diff --git a/panels/region/supported-ibus-engines.h b/panels/region/supported-ibus-engines.h
new file mode 100644
index 0000000..33e60f9
--- /dev/null
+++ b/panels/region/supported-ibus-engines.h
@@ -0,0 +1,212 @@
+static const gchar *supported_ibus_engines[] = {
+  /* Simplified Chinese */
+  "pinyin",
+  "bopomofo",
+  "wubi",
+  "erbi",
+  /* Default in Fedora, where ibus-libpinyin replaces ibus-pinyin */
+  "libpinyin",
+  "libbopomofo",
+
+  /* Traditional Chinese */
+  /* https://bugzilla.gnome.org/show_bug.cgi?id=680840 */
+  "chewing",
+  "cangjie5",
+  "cangjie3",
+  "quick5",
+  "quick3",
+  "stroke5",
+
+  /* Japanese */
+  "anthy",
+  "mozc-jp",
+  "skk",
+
+  /* Korean */
+  "hangul",
+
+  /* Thai */
+  "m17n:th:kesmanee",
+  "m17n:th:pattachote",
+  "m17n:th:tis820",
+
+  /* Vietnamese */
+  "m17n:vi:tcvn",
+  "m17n:vi:telex",
+  "m17n:vi:viqr",
+  "m17n:vi:vni",
+  "Unikey",
+
+  /* Sinhala */
+  "m17n:si:wijesekera",
+  "m17n:si:phonetic-dynamic",
+  "m17n:si:trans",
+  "sayura",
+
+  /* Indic */
+  /* https://fedoraproject.org/wiki/I18N/Indic#Keyboard_Layouts */
+
+  /* Assamese */
+  "m17n:as:phonetic",
+  "m17n:as:inscript",
+  "m17n:as:itrans",
+
+  /* Bengali */
+  "m17n:bn:inscript",
+  "m17n:bn:itrans",
+  "m17n:bn:probhat",
+
+  /* Gujarati */
+  "m17n:gu:inscript",
+  "m17n:gu:itrans",
+  "m17n:gu:phonetic",
+
+  /* Hindi */
+  "m17n:hi:inscript",
+  "m17n:hi:itrans",
+  "m17n:hi:phonetic",
+  "m17n:hi:remington",
+  "m17n:hi:typewriter",
+  "m17n:hi:vedmata",
+
+  /* Kannada */
+  "m17n:kn:kgp",
+  "m17n:kn:inscript",
+  "m17n:kn:itrans",
+
+  /* Kashmiri */
+  "m17n:ks:inscript",
+
+  /* Maithili */
+  "m17n:mai:inscript",
+
+  /* Malayalam */
+  "m17n:ml:inscript",
+  "m17n:ml:itrans",
+  "m17n:ml:mozhi",
+  "m17n:ml:swanalekha",
+
+  /* Marathi */
+  "m17n:mr:inscript",
+  "m17n:mr:itrans",
+  "m17n:mr:phonetic",
+
+  /* Nepali */
+  "m17n:ne:rom",
+  "m17n:ne:trad",
+
+  /* Oriya */
+  "m17n:or:inscript",
+  "m17n:or:itrans",
+  "m17n:or:phonetic",
+
+  /* Punjabi */
+  "m17n:pa:inscript",
+  "m17n:pa:itrans",
+  "m17n:pa:phonetic",
+  "m17n:pa:jhelum",
+
+  /* Sanskrit */
+  "m17n:sa:harvard-kyoto",
+
+  /* Sindhi */
+  "m17n:sd:inscript",
+
+  /* Tamil */
+  "m17n:ta:tamil99",
+  "m17n:ta:inscript",
+  "m17n:ta:itrans",
+  "m17n:ta:phonetic",
+  "m17n:ta:lk-renganathan",
+  "m17n:ta:vutam",
+  "m17n:ta:typewriter",
+
+  /* Telugu */
+  "m17n:te:inscript",
+  "m17n:te:apple",
+  "m17n:te:pothana",
+  "m17n:te:rts",
+
+  /* Urdu */
+  "m17n:ur:phonetic",
+
+  /* Inscript2 - https://bugzilla.gnome.org/show_bug.cgi?id=684854 */
+  "m17n:as:inscript2",
+  "m17n:bn:inscript2",
+  "m17n:brx:inscript2-deva",
+  "m17n:doi:inscript2-deva",
+  "m17n:gu:inscript2",
+  "m17n:hi:inscript2",
+  "m17n:kn:inscript2",
+  "m17n:kok:inscript2-deva",
+  "m17n:mai:inscript2",
+  "m17n:ml:inscript2",
+  "m17n:mni:inscript2-beng",
+  "m17n:mni:inscript2-mtei",
+  "m17n:mr:inscript2",
+  "m17n:ne:inscript2-deva",
+  "m17n:or:inscript2",
+  "m17n:pa:inscript2-guru",
+  "m17n:sa:inscript2",
+  "m17n:sat:inscript2-deva",
+  "m17n:sat:inscript2-olck",
+  "m17n:sd:inscript2-deva",
+  "m17n:ta:inscript2",
+  "m17n:te:inscript2",
+
+  /* No corresponding XKB map available for the languages */
+
+  /* Chinese Yi */
+  "m17n:ii:phonetic",
+
+  /* Tai-Viet */
+  "m17n:tai:sonla",
+
+  /* Kazakh in Arabic script */
+  "m17n:kk:arabic",
+
+  /* Yiddish */
+  "m17n:yi:yivo",
+
+  /* Canadian Aboriginal languages */
+  "m17n:ath:phonetic",
+  "m17n:bla:phonetic",
+  "m17n:cr:western",
+  "m17n:iu:phonetic",
+  "m17n:nsk:phonetic",
+  "m17n:oj:phonetic",
+
+  /* Non-trivial engines, like transliteration-based instead of
+     keymap-based.  Confirmation needed that the engines below are
+     actually used by local language users. */
+
+  /* Tibetan */
+  "m17n:bo:ewts",
+  "m17n:bo:tcrc",
+  "m17n:bo:wylie",
+
+  /* Esperanto */
+  "m17n:eo:h-f",
+  "m17n:eo:h",
+  "m17n:eo:plena",
+  "m17n:eo:q",
+  "m17n:eo:vi",
+  "m17n:eo:x",
+
+  /* Amharic */
+  "m17n:am:sera",
+
+  /* Russian */
+  "m17n:ru:translit",
+
+  /* Classical Greek */
+  "m17n:grc:mizuochi",
+
+  /* Lao */
+  "m17n:lo:lrt",
+
+  /* Postfix modifier input methods */
+  "m17n:da:post",
+  "m17n:sv:post",
+  NULL
+};


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