[gnome-initial-setup] Add a region chooser
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-initial-setup] Add a region chooser
- Date: Fri, 6 Dec 2013 22:53:59 +0000 (UTC)
commit 18cac64c2eca8189779873d8979980a0cf64da67
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Dec 6 09:45:29 2013 -0500
Add a region chooser
Now that the language chooser only shows languages, we add
a separate step to select a region for given language. Under
the covers, both steps select a complete locale. The language
page just selects the first locale with a given locale. The
region page shows all the locales with the same language.
If there is only one region, we skip this page altogether.
configure.ac | 1 +
gnome-initial-setup/Makefile.am | 1 +
gnome-initial-setup/gnome-initial-setup.c | 2 +
gnome-initial-setup/pages/Makefile.am | 1 +
gnome-initial-setup/pages/region/Makefile.am | 30 +
.../pages/region/cc-common-language.c | 326 ++++++++++
.../pages/region/cc-common-language.h | 36 +
.../pages/region/cc-region-chooser.c | 671 ++++++++++++++++++++
.../pages/region/cc-region-chooser.h | 64 ++
gnome-initial-setup/pages/region/gis-region-page.c | 279 ++++++++
gnome-initial-setup/pages/region/gis-region-page.h | 59 ++
.../pages/region/gis-region-page.ui | 62 ++
gnome-initial-setup/pages/region/region-chooser.ui | 37 ++
.../pages/region/region.gresource.xml | 9 +
14 files changed, 1578 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 9ed91df..6d6eab0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -101,6 +101,7 @@ data/Makefile
gnome-initial-setup/Makefile
gnome-initial-setup/pages/Makefile
gnome-initial-setup/pages/language/Makefile
+gnome-initial-setup/pages/region/Makefile
gnome-initial-setup/pages/keyboard/Makefile
gnome-initial-setup/pages/eulas/Makefile
gnome-initial-setup/pages/network/Makefile
diff --git a/gnome-initial-setup/Makefile.am b/gnome-initial-setup/Makefile.am
index 478f7f5..34a3da9 100644
--- a/gnome-initial-setup/Makefile.am
+++ b/gnome-initial-setup/Makefile.am
@@ -29,6 +29,7 @@ gnome_initial_setup_SOURCES = \
gnome_initial_setup_LDADD = \
pages/language/libgislanguage.la \
+ pages/region/libgisregion.la \
pages/keyboard/libgiskeyboard.la \
pages/eulas/libgiseulas.la \
pages/network/libgisnetwork.la \
diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c
index c0ae5a7..33f7968 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -39,6 +39,7 @@
#endif
#include "pages/language/gis-language-page.h"
+#include "pages/region/gis-region-page.h"
#include "pages/keyboard/gis-keyboard-page.h"
#include "pages/eulas/gis-eula-pages.h"
#include "pages/network/gis-network-page.h"
@@ -61,6 +62,7 @@ typedef struct {
static PageData page_table[] = {
PAGE (language, FALSE),
+ PAGE (region, FALSE),
PAGE (keyboard, FALSE),
PAGE (eula, FALSE),
PAGE (network, FALSE),
diff --git a/gnome-initial-setup/pages/Makefile.am b/gnome-initial-setup/pages/Makefile.am
index c52def6..9292b05 100644
--- a/gnome-initial-setup/pages/Makefile.am
+++ b/gnome-initial-setup/pages/Makefile.am
@@ -1,6 +1,7 @@
SUBDIRS = \
language \
+ region \
keyboard \
eulas \
network \
diff --git a/gnome-initial-setup/pages/region/Makefile.am b/gnome-initial-setup/pages/region/Makefile.am
new file mode 100644
index 0000000..95a971c
--- /dev/null
+++ b/gnome-initial-setup/pages/region/Makefile.am
@@ -0,0 +1,30 @@
+
+noinst_LTLIBRARIES = libgisregion.la
+
+AM_CPPFLAGS = \
+ -I"$(top_srcdir)" \
+ -I"$(top_srcdir)/gnome-initial-setup" \
+ -I"$(top_builddir)" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\"
+
+BUILT_SOURCES =
+
+resource_files = $(shell glib-compile-resources --sourcedir=$(srcdir) --generate-dependencies
$(srcdir)/region.gresource.xml)
+region-resources.c: region.gresource.xml $(resource_files)
+ $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate-source $<
+region-resources.h: region.gresource.xml $(resource_files)
+ $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate-header $<
+BUILT_SOURCES += region-resources.c region-resources.h
+
+libgisregion_la_SOURCES = \
+ cc-common-language.c cc-common-language.h \
+ cc-region-chooser.c cc-region-chooser.h \
+ gis-region-page.c gis-region-page.h \
+ $(BUILT_SOURCES)
+
+libgisregion_la_CFLAGS = $(INITIAL_SETUP_CFLAGS)
+libgisregion_la_LIBADD = $(INITIAL_SETUP_LIBS)
+libgisregion_la_LDFLAGS = -export_dynamic -avoid-version -module -no-undefined
+
+EXTRA_DIST = region.gresource.xml $(resource_files)
diff --git a/gnome-initial-setup/pages/region/cc-common-language.c
b/gnome-initial-setup/pages/region/cc-common-language.c
new file mode 100644
index 0000000..04f0c84
--- /dev/null
+++ b/gnome-initial-setup/pages/region/cc-common-language.c
@@ -0,0 +1,326 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009-2010 Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <fontconfig/fontconfig.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-languages.h>
+
+#include "cc-common-language.h"
+
+static char *get_lang_for_user_object_path (const char *path);
+
+gboolean
+cc_common_language_has_font (const gchar *locale)
+{
+ const FcCharSet *charset;
+ FcPattern *pattern;
+ FcObjectSet *object_set;
+ FcFontSet *font_set;
+ gchar *language_code;
+ gboolean is_displayable;
+
+ is_displayable = FALSE;
+ pattern = NULL;
+ object_set = NULL;
+ font_set = NULL;
+
+ if (!gnome_parse_locale (locale, &language_code, NULL, NULL, NULL))
+ return FALSE;
+
+ charset = FcLangGetCharSet ((FcChar8 *) language_code);
+ if (!charset) {
+ /* fontconfig does not know about this language */
+ is_displayable = TRUE;
+ }
+ else {
+ /* see if any fonts support rendering it */
+ pattern = FcPatternBuild (NULL, FC_LANG, FcTypeString, language_code, NULL);
+
+ if (pattern == NULL)
+ goto done;
+
+ object_set = FcObjectSetCreate ();
+
+ if (object_set == NULL)
+ goto done;
+
+ font_set = FcFontList (NULL, pattern, object_set);
+
+ if (font_set == NULL)
+ goto done;
+
+ is_displayable = (font_set->nfont > 0);
+ }
+
+ done:
+ if (font_set != NULL)
+ FcFontSetDestroy (font_set);
+
+ if (object_set != NULL)
+ FcObjectSetDestroy (object_set);
+
+ if (pattern != NULL)
+ FcPatternDestroy (pattern);
+
+ g_free (language_code);
+
+ return is_displayable;
+}
+
+gchar *
+cc_common_language_get_current_language (void)
+{
+ gchar *language;
+ char *path;
+ const gchar *locale;
+
+ path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", getuid ());
+ language = get_lang_for_user_object_path (path);
+ g_free (path);
+ if (language != NULL && *language != '\0')
+ return language;
+
+ locale = (const gchar *) setlocale (LC_MESSAGES, NULL);
+ if (locale)
+ language = gnome_normalize_locale (locale);
+ else
+ language = NULL;
+
+ return language;
+}
+
+static gboolean
+user_language_has_translations (const char *locale)
+{
+ char *name, *language_code, *territory_code;
+ gboolean ret;
+
+ gnome_parse_locale (locale,
+ &language_code,
+ &territory_code,
+ NULL, NULL);
+ name = g_strdup_printf ("%s%s%s",
+ language_code,
+ territory_code != NULL? "_" : "",
+ territory_code != NULL? territory_code : "");
+ g_free (language_code);
+ g_free (territory_code);
+ ret = gnome_language_has_translations (name);
+ g_free (name);
+
+ return ret;
+}
+
+static char *
+get_lang_for_user_object_path (const char *path)
+{
+ GError *error = NULL;
+ GDBusProxy *user;
+ GVariant *props;
+ char *lang;
+
+ user = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.Accounts",
+ path,
+ "org.freedesktop.Accounts.User",
+ NULL,
+ &error);
+ if (user == NULL) {
+ g_warning ("Failed to get proxy for user '%s': %s",
+ path, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+ props = g_dbus_proxy_get_cached_property (user, "Language");
+ lang = g_variant_dup_string (props, NULL);
+
+ g_variant_unref (props);
+ g_object_unref (user);
+ return lang;
+}
+
+static void
+add_other_users_language (GHashTable *ht)
+{
+ GVariant *variant;
+ GVariantIter *vi;
+ GError *error = NULL;
+ const char *str;
+ GDBusProxy *proxy;
+
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.Accounts",
+ "/org/freedesktop/Accounts",
+ "org.freedesktop.Accounts",
+ NULL,
+ NULL);
+
+ if (proxy == NULL)
+ return;
+
+ variant = g_dbus_proxy_call_sync (proxy,
+ "ListCachedUsers",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (variant == NULL) {
+ g_warning ("Failed to list existing users: %s", error->message);
+ g_error_free (error);
+ g_object_unref (proxy);
+ return;
+ }
+ g_variant_get (variant, "(ao)", &vi);
+ while (g_variant_iter_loop (vi, "o", &str)) {
+ char *lang;
+ char *name;
+ char *language;
+
+ lang = get_lang_for_user_object_path (str);
+ if (lang != NULL && *lang != '\0' &&
+ cc_common_language_has_font (lang) &&
+ user_language_has_translations (lang)) {
+ name = gnome_normalize_locale (lang);
+ if (!g_hash_table_lookup (ht, name)) {
+ language = gnome_get_language_from_locale (name, NULL);
+ g_hash_table_insert (ht, name, language);
+ }
+ else {
+ g_free (name);
+ }
+ }
+ g_free (lang);
+ }
+ g_variant_iter_free (vi);
+ g_variant_unref (variant);
+
+ g_object_unref (proxy);
+}
+
+static void
+insert_language_internal (GHashTable *ht,
+ const char *lang)
+{
+ gboolean has_translations;
+ char *label_own_lang;
+ char *label_current_lang;
+ char *label_untranslated;
+ char *key;
+
+ has_translations = gnome_language_has_translations (lang);
+ if (!has_translations) {
+ char *lang_code = g_strndup (lang, 2);
+ has_translations = gnome_language_has_translations (lang_code);
+ g_free (lang_code);
+
+ if (!has_translations)
+ return;
+ }
+
+ g_debug ("We have translations for %s", lang);
+
+ key = g_strdup (lang);
+
+ label_own_lang = gnome_get_language_from_locale (key, key);
+ label_current_lang = gnome_get_language_from_locale (key, NULL);
+ label_untranslated = gnome_get_language_from_locale (key, "C");
+
+ /* We don't have a translation for the label in
+ * its own language? */
+ if (g_strcmp0 (label_own_lang, label_untranslated) == 0) {
+ if (g_strcmp0 (label_current_lang, label_untranslated) == 0)
+ g_hash_table_insert (ht, key, g_strdup (label_untranslated));
+ else
+ g_hash_table_insert (ht, key, g_strdup (label_current_lang));
+ } else {
+ g_hash_table_insert (ht, key, g_strdup (label_own_lang));
+ }
+
+ g_free (label_own_lang);
+ g_free (label_current_lang);
+ g_free (label_untranslated);
+}
+
+static void
+insert_language (GHashTable *ht,
+ const char *lang)
+{
+ char *utf8_variant = g_strconcat (lang, ".utf8", NULL);
+ insert_language_internal (ht, lang);
+ insert_language_internal (ht, utf8_variant);
+ g_free (utf8_variant);
+}
+
+static void
+insert_user_languages (GHashTable *ht)
+{
+ char *name;
+ char *language;
+
+ /* Add the languages used by other users on the system */
+ add_other_users_language (ht);
+
+ /* Add current locale */
+ name = cc_common_language_get_current_language ();
+ if (g_hash_table_lookup (ht, name) == NULL) {
+ language = gnome_get_language_from_locale (name, NULL);
+ g_hash_table_insert (ht, name, language);
+ } else {
+ g_free (name);
+ }
+}
+
+GHashTable *
+cc_common_language_get_initial_languages (void)
+{
+ GHashTable *ht;
+
+ ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ insert_language (ht, "en_US");
+ insert_language (ht, "en_GB");
+ insert_language (ht, "de_DE");
+ insert_language (ht, "fr_FR");
+ insert_language (ht, "es_ES");
+ insert_language (ht, "zh_CN");
+ insert_language (ht, "ja_JP");
+ insert_language (ht, "ru_RU");
+ insert_language (ht, "ar_EG");
+
+ insert_user_languages (ht);
+
+ return ht;
+}
diff --git a/gnome-initial-setup/pages/region/cc-common-language.h
b/gnome-initial-setup/pages/region/cc-common-language.h
new file mode 100644
index 0000000..7f32cab
--- /dev/null
+++ b/gnome-initial-setup/pages/region/cc-common-language.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009-2010 Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ * Written by: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __CC_COMMON_LANGUAGE_H__
+#define __CC_COMMON_LANGUAGE_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+gboolean cc_common_language_has_font (const gchar *locale);
+gchar *cc_common_language_get_current_language (void);
+GHashTable *cc_common_language_get_initial_languages (void);
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-initial-setup/pages/region/cc-region-chooser.c
b/gnome-initial-setup/pages/region/cc-region-chooser.c
new file mode 100644
index 0000000..3b98847
--- /dev/null
+++ b/gnome-initial-setup/pages/region/cc-region-chooser.c
@@ -0,0 +1,671 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Red Hat
+ *
+ * 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:
+ * Jasper St. Pierre <jstpierre mecheye net>
+ * Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+#include "cc-region-chooser.h"
+
+#include <locale.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <gtk/gtk.h>
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-languages.h>
+
+#include "cc-common-language.h"
+
+#include <glib-object.h>
+
+#define MIN_ROWS 6
+
+struct _CcRegionChooserPrivate
+{
+ GtkWidget *filter_entry;
+ GtkWidget *region_list;
+
+ GtkWidget *scrolled_window;
+ GtkWidget *no_results;
+ GtkWidget *more_item;
+
+ GHashTable *regions;
+
+ gboolean showing_extra;
+ gchar *locale;
+ gchar *lang;
+};
+typedef struct _CcRegionChooserPrivate CcRegionChooserPrivate;
+G_DEFINE_TYPE_WITH_PRIVATE (CcRegionChooser, cc_region_chooser, GTK_TYPE_BOX);
+
+enum {
+ PROP_0,
+ PROP_LOCALE,
+ PROP_SHOWING_EXTRA,
+ PROP_LAST,
+};
+
+static GParamSpec *obj_props[PROP_LAST];
+
+typedef struct {
+ GtkWidget *box;
+ GtkWidget *checkmark;
+
+ gchar *locale_id;
+ gchar *locale_name;
+ gchar *locale_current_name;
+ gchar *locale_untranslated_name;
+ gboolean is_extra;
+} RegionWidget;
+
+static RegionWidget *
+get_region_widget (GtkWidget *widget)
+{
+ return g_object_get_data (G_OBJECT (widget), "region-widget");
+}
+
+static GtkWidget *
+padded_label_new (char *text)
+{
+ GtkWidget *widget;
+ widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+ gtk_widget_set_halign (widget, GTK_ALIGN_CENTER);
+ gtk_widget_set_margin_top (widget, 10);
+ gtk_widget_set_margin_bottom (widget, 10);
+ gtk_box_pack_start (GTK_BOX (widget), gtk_label_new (text), FALSE, FALSE, 0);
+ return widget;
+}
+
+static void
+region_widget_free (gpointer data)
+{
+ RegionWidget *widget = data;
+
+ /* This is called when the box is destroyed,
+ * so don't bother destroying the widget and
+ * children again. */
+ g_free (widget->locale_id);
+ g_free (widget->locale_name);
+ g_free (widget->locale_current_name);
+ g_free (widget->locale_untranslated_name);
+ g_free (widget);
+}
+
+static char *
+get_country_name (const char *locale,
+ const char *translation)
+{
+ char *name;
+ char *p;
+
+ name = gnome_get_country_from_locale (locale, translation);
+ p = strstr (name, " (");
+ if (p)
+ *p = '\0';
+
+ return name;
+}
+
+static GtkWidget *
+region_widget_new (const char *locale_id,
+ const char *region,
+ gboolean is_extra)
+{
+ gchar *locale_name, *locale_current_name, *locale_untranslated_name;
+ GtkWidget *checkmark;
+ GtkWidget *label;
+ RegionWidget *widget = g_new0 (RegionWidget, 1);
+
+ locale_name = get_country_name (locale_id, locale_id);
+ locale_current_name = get_country_name (locale_id, NULL);
+ locale_untranslated_name = get_country_name (locale_id, "C");
+
+ widget->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+ gtk_widget_set_margin_top (widget->box, 10);
+ gtk_widget_set_margin_bottom (widget->box, 10);
+ gtk_widget_set_margin_start (widget->box, 10);
+ gtk_widget_set_margin_end (widget->box, 10);
+ gtk_widget_set_halign (widget->box, GTK_ALIGN_FILL);
+ label = gtk_label_new (locale_name);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_label_set_width_chars (GTK_LABEL (label), 40);
+ gtk_box_pack_start (GTK_BOX (widget->box), label, FALSE, FALSE, 0);
+ widget->locale_id = g_strdup (locale_id);
+ widget->locale_name = locale_name;
+ widget->locale_current_name = locale_current_name;
+ widget->locale_untranslated_name = locale_untranslated_name;
+ widget->is_extra = is_extra;
+
+ widget->checkmark = gtk_image_new_from_icon_name ("object-select-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_box_pack_start (GTK_BOX (widget->box), widget->checkmark, TRUE, TRUE, 0);
+ gtk_widget_set_halign (widget->checkmark, GTK_ALIGN_END);
+ gtk_widget_show_all (widget->box);
+
+ g_object_set_data_full (G_OBJECT (widget->box), "region-widget", widget,
+ region_widget_free);
+
+ return widget->box;
+}
+
+static void
+sync_checkmark (GtkWidget *row,
+ gpointer user_data)
+{
+ GtkWidget *child;
+ RegionWidget *widget;
+ gchar *locale_id;
+ gboolean should_be_visible;
+
+ child = gtk_bin_get_child (GTK_BIN (row));
+ widget = get_region_widget (child);
+
+ if (widget == NULL)
+ return;
+
+ locale_id = user_data;
+ should_be_visible = g_str_equal (widget->locale_id, locale_id);
+ gtk_widget_set_opacity (widget->checkmark, should_be_visible ? 1.0 : 0.0);
+}
+
+static void
+sync_all_checkmarks (CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+
+ gtk_container_foreach (GTK_CONTAINER (priv->region_list),
+ sync_checkmark, priv->locale);
+}
+
+static GtkWidget *
+more_widget_new (void)
+{
+ GtkWidget *widget;
+ GtkWidget *arrow;
+
+ widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+ gtk_widget_set_tooltip_text (widget, _("Moreā¦"));
+
+ arrow = gtk_image_new_from_icon_name ("view-more-symbolic", GTK_ICON_SIZE_MENU);
+ gtk_style_context_add_class (gtk_widget_get_style_context (arrow), "dim-label");
+ gtk_widget_set_margin_top (widget, 10);
+ gtk_widget_set_margin_bottom (widget, 10);
+ gtk_misc_set_alignment (GTK_MISC (arrow), 0.5, 0.5);
+ gtk_box_pack_start (GTK_BOX (widget), arrow, TRUE, TRUE, 0);
+
+ return widget;
+}
+
+static GtkWidget *
+no_results_widget_new (void)
+{
+ GtkWidget *widget;
+
+ widget = padded_label_new (_("No regions found"));
+ gtk_widget_set_sensitive (widget, FALSE);
+ return widget;
+}
+
+static void
+add_one_region (CcRegionChooser *chooser,
+ const char *locale_id)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ GtkWidget *widget;
+ gchar *lang = NULL;
+ gchar *region = NULL;
+ gboolean is_extra;
+
+ if (!g_str_has_suffix (locale_id, "utf8")) {
+ return;
+ }
+
+ if (!cc_common_language_has_font (locale_id)) {
+ return;
+ }
+
+ if (!gnome_parse_locale (locale_id, &lang, ®ion, NULL, NULL)) {
+ goto out;
+ }
+
+ if (g_strcmp0 (priv->lang, lang) != 0) {
+ goto out;
+ }
+
+ if (region == NULL) {
+ goto out;
+ }
+
+ if (g_hash_table_contains (priv->regions, region)) {
+ goto out;
+ }
+ g_hash_table_add (priv->regions, g_strdup (region));
+ if (g_hash_table_size (priv->regions) > MIN_ROWS)
+ is_extra = TRUE;
+ else
+ is_extra = FALSE;
+
+ widget = region_widget_new (locale_id, region, is_extra);
+ gtk_container_add (GTK_CONTAINER (priv->region_list), widget);
+
+out:
+ g_free (lang);
+ g_free (region);
+}
+
+static void
+add_regions (CcRegionChooser *chooser,
+ char **locale_ids,
+ GHashTable *initial)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ GHashTableIter iter;
+ gchar *key;
+
+ add_one_region (chooser, priv->locale);
+
+ g_hash_table_iter_init (&iter, initial);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL)) {
+ add_one_region (chooser, key);
+ }
+
+ while (*locale_ids) {
+ const gchar *locale_id;
+
+ locale_id = *locale_ids;
+ locale_ids ++;
+
+ add_one_region (chooser, locale_id);
+ }
+
+ gtk_container_add (GTK_CONTAINER (priv->region_list), priv->more_item);
+
+ gtk_widget_show_all (priv->region_list);
+}
+
+static void
+add_all_regions (CcRegionChooser *chooser)
+{
+ char **locale_ids;
+ GHashTable *initial;
+
+ locale_ids = gnome_get_all_locales ();
+ initial = cc_common_language_get_initial_languages ();
+ add_regions (chooser, locale_ids, initial);
+ g_hash_table_destroy (initial);
+ g_strfreev (locale_ids);
+}
+
+static gboolean
+region_visible (GtkListBoxRow *row,
+ gpointer user_data)
+{
+ CcRegionChooser *chooser = user_data;
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ RegionWidget *widget;
+ gboolean visible;
+ GtkWidget *child;
+ const char *search_term;
+
+ child = gtk_bin_get_child (GTK_BIN (row));
+ if (child == priv->more_item)
+ return !priv->showing_extra && g_hash_table_size (priv->regions) > MIN_ROWS;
+
+ widget = get_region_widget (child);
+
+ if (!priv->showing_extra && widget->is_extra)
+ return FALSE;
+
+ search_term = gtk_entry_get_text (GTK_ENTRY (priv->filter_entry));
+ if (!search_term || !*search_term)
+ return TRUE;
+
+ visible = FALSE;
+
+ visible = g_str_match_string (search_term, widget->locale_name, TRUE);
+ if (visible)
+ goto out;
+
+ visible = g_str_match_string (search_term, widget->locale_current_name, TRUE);
+ if (visible)
+ goto out;
+
+ visible = g_str_match_string (search_term, widget->locale_untranslated_name, TRUE);
+ if (visible)
+ goto out;
+
+ out:
+ return visible;
+}
+
+static gint
+sort_regions (GtkListBoxRow *a,
+ GtkListBoxRow *b,
+ gpointer data)
+{
+ RegionWidget *la, *lb;
+
+ la = get_region_widget (gtk_bin_get_child (GTK_BIN (a)));
+ lb = get_region_widget (gtk_bin_get_child (GTK_BIN (b)));
+
+ if (la == NULL)
+ return 1;
+
+ if (lb == NULL)
+ return -1;
+
+ if (la->is_extra && !lb->is_extra)
+ return 1;
+
+ if (!la->is_extra && lb->is_extra)
+ return -1;
+
+ return strcmp (la->locale_name, lb->locale_name);
+}
+
+static void
+filter_changed (GtkEntry *entry,
+ CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->region_list));
+}
+
+static void
+show_more (CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ if (g_hash_table_size (priv->regions) <= MIN_ROWS)
+ return;
+
+ gtk_widget_show (priv->filter_entry);
+ gtk_widget_grab_focus (priv->filter_entry);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_valign (GTK_WIDGET (chooser), GTK_ALIGN_FILL);
+
+ priv->showing_extra = TRUE;
+ gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->region_list));
+ g_object_notify_by_pspec (G_OBJECT (chooser), obj_props[PROP_SHOWING_EXTRA]);
+}
+
+static void
+show_less (CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+
+ gtk_widget_hide (priv->filter_entry);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_NEVER);
+ gtk_widget_set_valign (GTK_WIDGET (chooser), GTK_ALIGN_START);
+
+ priv->showing_extra = FALSE;
+ gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->region_list));
+ g_object_notify_by_pspec (G_OBJECT (chooser), obj_props[PROP_SHOWING_EXTRA]);
+}
+
+static void
+remove_regions (CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ GtkContainer *container;
+ GList *children, *l;
+
+ container = GTK_CONTAINER (priv->region_list);
+
+ children = gtk_container_get_children (container);
+ for (l = children; l; l = l->next) {
+ if (l->data != gtk_widget_get_parent (priv->more_item))
+ gtk_container_remove (container, l->data);
+ }
+ g_list_free (children);
+
+ g_hash_table_remove_all (priv->regions);
+}
+
+static void
+set_locale_id (CcRegionChooser *chooser,
+ const gchar *new_locale_id)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ gchar *new_lang;
+
+ if (g_strcmp0 (priv->locale, new_locale_id) == 0)
+ return;
+
+ g_free (priv->locale);
+ priv->locale = g_strdup (new_locale_id);
+
+ gnome_parse_locale (new_locale_id, &new_lang, NULL, NULL, NULL);
+ if (g_strcmp0 (priv->lang, new_lang) != 0) {
+ g_free (priv->lang);
+ priv->lang = g_strdup (new_lang);
+
+ remove_regions (chooser);
+ show_less (chooser);
+ add_all_regions (chooser);
+ }
+ g_free (new_lang);
+
+ sync_all_checkmarks (chooser);
+
+ g_object_notify_by_pspec (G_OBJECT (chooser), obj_props[PROP_LOCALE]);
+}
+
+static void
+row_activated (GtkListBox *box,
+ GtkListBoxRow *row,
+ CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ GtkWidget *child;
+ RegionWidget *widget;
+
+ if (row == NULL)
+ return;
+
+ child = gtk_bin_get_child (GTK_BIN (row));
+ if (child == priv->more_item) {
+ show_more (chooser);
+ } else {
+ widget = get_region_widget (child);
+ if (widget == NULL)
+ return;
+ set_locale_id (chooser, widget->locale_id);
+ }
+}
+
+static void
+update_header_func (GtkListBoxRow *child,
+ GtkListBoxRow *before,
+ gpointer user_data)
+{
+ GtkWidget *header;
+
+ if (before == NULL)
+ return;
+
+ header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_list_box_row_set_header (child, header);
+ gtk_widget_show (header);
+}
+
+static void
+cc_region_chooser_constructed (GObject *object)
+{
+ CcRegionChooser *chooser = CC_REGION_CHOOSER (object);
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+
+ G_OBJECT_CLASS (cc_region_chooser_parent_class)->constructed (object);
+
+ priv->more_item = more_widget_new ();
+ priv->no_results = no_results_widget_new ();
+
+ priv->regions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ gtk_list_box_set_sort_func (GTK_LIST_BOX (priv->region_list),
+ sort_regions, chooser, NULL);
+ gtk_list_box_set_filter_func (GTK_LIST_BOX (priv->region_list),
+ region_visible, chooser, NULL);
+ gtk_list_box_set_header_func (GTK_LIST_BOX (priv->region_list),
+ update_header_func, chooser, NULL);
+ gtk_list_box_set_selection_mode (GTK_LIST_BOX (priv->region_list),
+ GTK_SELECTION_NONE);
+
+ gtk_list_box_set_placeholder (GTK_LIST_BOX (priv->region_list), priv->no_results);
+
+ if (priv->locale == NULL) {
+ priv->locale = cc_common_language_get_current_language ();
+ gnome_parse_locale (priv->locale, &priv->lang, NULL, NULL, NULL);
+ }
+
+ add_all_regions (chooser);
+
+ g_signal_connect (priv->filter_entry, "changed",
+ G_CALLBACK (filter_changed),
+ chooser);
+
+ g_signal_connect (priv->region_list, "row-activated",
+ G_CALLBACK (row_activated), chooser);
+
+ sync_all_checkmarks (chooser);
+}
+
+static void
+cc_region_chooser_finalize (GObject *object)
+{
+ CcRegionChooser *chooser = CC_REGION_CHOOSER (object);
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+
+ g_hash_table_unref (priv->regions);
+
+ G_OBJECT_CLASS (cc_region_chooser_parent_class)->finalize (object);
+}
+
+static void
+cc_region_chooser_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CcRegionChooser *chooser = CC_REGION_CHOOSER (object);
+ switch (prop_id) {
+ case PROP_LOCALE:
+ g_value_set_string (value, cc_region_chooser_get_locale (chooser));
+ break;
+ case PROP_SHOWING_EXTRA:
+ g_value_set_boolean (value, cc_region_chooser_get_showing_extra (chooser));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+cc_region_chooser_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CcRegionChooser *chooser = CC_REGION_CHOOSER (object);
+ switch (prop_id) {
+ case PROP_LOCALE:
+ cc_region_chooser_set_locale (chooser, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+cc_region_chooser_class_init (CcRegionChooserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass),
"/org/gnome/control-center/region-chooser.ui");
+
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), CcRegionChooser,
filter_entry);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), CcRegionChooser,
region_list);
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), CcRegionChooser,
scrolled_window);
+
+ object_class->finalize = cc_region_chooser_finalize;
+ object_class->get_property = cc_region_chooser_get_property;
+ object_class->set_property = cc_region_chooser_set_property;
+ object_class->constructed = cc_region_chooser_constructed;
+
+ obj_props[PROP_LOCALE] =
+ g_param_spec_string ("locale", "", "", "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ obj_props[PROP_SHOWING_EXTRA] =
+ g_param_spec_string ("showing-extra", "", "", "",
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, PROP_LAST, obj_props);
+}
+
+static void
+cc_region_chooser_init (CcRegionChooser *chooser)
+{
+ gtk_widget_init_template (GTK_WIDGET (chooser));
+}
+
+void
+cc_region_chooser_clear_filter (CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ gtk_entry_set_text (GTK_ENTRY (priv->filter_entry), "");
+}
+
+const gchar *
+cc_region_chooser_get_locale (CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ return priv->locale;
+}
+
+void
+cc_region_chooser_set_locale (CcRegionChooser *chooser,
+ const gchar *locale)
+{
+ set_locale_id (chooser, locale);
+}
+
+gboolean
+cc_region_chooser_get_showing_extra (CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ return priv->showing_extra;
+}
+
+gint
+cc_region_chooser_get_n_regions (CcRegionChooser *chooser)
+{
+ CcRegionChooserPrivate *priv = cc_region_chooser_get_instance_private (chooser);
+ return g_hash_table_size (priv->regions);
+}
diff --git a/gnome-initial-setup/pages/region/cc-region-chooser.h
b/gnome-initial-setup/pages/region/cc-region-chooser.h
new file mode 100644
index 0000000..62545fb
--- /dev/null
+++ b/gnome-initial-setup/pages/region/cc-region-chooser.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Red Hat
+ *
+ * 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:
+ * Jasper St. Pierre <jstpierre mecheye net>
+ * Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __CC_REGION_CHOOSER_H__
+#define __CC_REGION_CHOOSER_H__
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+#define CC_TYPE_REGION_CHOOSER (cc_region_chooser_get_type ())
+#define CC_REGION_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TYPE_REGION_CHOOSER,
CcRegionChooser))
+#define CC_REGION_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CC_TYPE_REGION_CHOOSER,
CcRegionChooserClass))
+#define CC_IS_REGION_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TYPE_REGION_CHOOSER))
+#define CC_IS_REGION_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_TYPE_REGION_CHOOSER))
+#define CC_REGION_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_TYPE_REGION_CHOOSER,
CcRegionChooserClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CcRegionChooser CcRegionChooser;
+typedef struct _CcRegionChooserClass CcRegionChooserClass;
+
+struct _CcRegionChooser
+{
+ GtkBox parent;
+};
+
+struct _CcRegionChooserClass
+{
+ GtkBoxClass parent_class;
+};
+
+GType cc_region_chooser_get_type (void);
+
+void cc_region_chooser_clear_filter (CcRegionChooser *chooser);
+const gchar * cc_region_chooser_get_locale (CcRegionChooser *chooser);
+void cc_region_chooser_set_locale (CcRegionChooser *chooser,
+ const gchar *locale);
+gboolean cc_region_chooser_get_showing_extra (CcRegionChooser *chooser);
+gint cc_region_chooser_get_n_regions (CcRegionChooser *chooser);
+
+G_END_DECLS
+
+#endif /* __CC_REGION_CHOOSER_H__ */
diff --git a/gnome-initial-setup/pages/region/gis-region-page.c
b/gnome-initial-setup/pages/region/gis-region-page.c
new file mode 100644
index 0000000..bd6ea53
--- /dev/null
+++ b/gnome-initial-setup/pages/region/gis-region-page.c
@@ -0,0 +1,279 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2013 Red Hat
+ *
+ * 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 <mclasen redhat com>
+ *
+ * Based on gnome-control-center cc-region-panel.c
+ */
+
+/* Region page {{{1 */
+
+#define PAGE_ID "region"
+
+#include "config.h"
+#include "region-resources.h"
+#include "cc-region-chooser.h"
+#include "cc-common-language.h"
+#include "gis-region-page.h"
+
+#include <act/act-user-manager.h>
+#include <polkit/polkit.h>
+#include <locale.h>
+#include <gtk/gtk.h>
+
+struct _GisRegionPagePrivate
+{
+ GtkWidget *region_chooser;
+
+ GDBusProxy *localed;
+ GPermission *permission;
+ const gchar *new_locale_id;
+ gboolean updating;
+
+ GCancellable *cancellable;
+};
+typedef struct _GisRegionPagePrivate GisRegionPagePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GisRegionPage, gis_region_page, GIS_TYPE_PAGE);
+
+static void
+set_localed_locale (GisRegionPage *self)
+{
+ GisRegionPagePrivate *priv = gis_region_page_get_instance_private (self);
+ GVariantBuilder *b;
+ gchar *s;
+
+ b = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+ s = g_strconcat ("LANG=", priv->new_locale_id, NULL);
+ g_variant_builder_add (b, "s", s);
+ g_free (s);
+
+ g_dbus_proxy_call (priv->localed,
+ "SetLocale",
+ g_variant_new ("(asb)", b, TRUE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, NULL, NULL);
+ g_variant_builder_unref (b);
+}
+
+static void
+change_locale_permission_acquired (GObject *source,
+ GAsyncResult *res,
+ gpointer data)
+{
+ GisRegionPage *page = GIS_REGION_PAGE (data);
+ GisRegionPagePrivate *priv = gis_region_page_get_instance_private (page);
+ GError *error = NULL;
+ gboolean allowed;
+
+ allowed = g_permission_acquire_finish (priv->permission, res, &error);
+ if (error) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Failed to acquire permission: %s\n", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (allowed)
+ set_localed_locale (page);
+}
+
+static void
+user_loaded (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ gchar *new_locale_id = user_data;
+
+ act_user_set_language (ACT_USER (object), new_locale_id);
+
+ g_free (new_locale_id);
+}
+
+static void
+region_changed (CcRegionChooser *chooser,
+ GParamSpec *pspec,
+ GisRegionPage *page)
+{
+ GisRegionPagePrivate *priv = gis_region_page_get_instance_private (page);
+ ActUser *user;
+ GisDriver *driver;
+
+ if (priv->updating)
+ return;
+
+ priv->new_locale_id = cc_region_chooser_get_locale (chooser);
+ driver = GIS_PAGE (page)->driver;
+
+ setlocale (LC_MESSAGES, priv->new_locale_id);
+ gis_driver_locale_changed (driver);
+
+ if (gis_driver_get_mode (driver) == GIS_DRIVER_MODE_NEW_USER) {
+ if (g_permission_get_allowed (priv->permission)) {
+ set_localed_locale (page);
+ }
+ else if (g_permission_get_can_acquire (priv->permission)) {
+ g_permission_acquire_async (priv->permission,
+ NULL,
+ change_locale_permission_acquired,
+ page);
+ }
+ }
+ user = act_user_manager_get_user (act_user_manager_get_default (),
+ g_get_user_name ());
+ if (act_user_is_loaded (user))
+ act_user_set_language (user, priv->new_locale_id);
+ else
+ g_signal_connect (user,
+ "notify::is-loaded",
+ G_CALLBACK (user_loaded),
+ g_strdup (priv->new_locale_id));
+
+ gis_driver_set_user_language (driver, priv->new_locale_id);
+}
+
+static void
+localed_proxy_ready (GObject *source,
+ GAsyncResult *res,
+ gpointer data)
+{
+ GisRegionPage *self = data;
+ GisRegionPagePrivate *priv = gis_region_page_get_instance_private (self);
+ GDBusProxy *proxy;
+ GError *error = NULL;
+
+ proxy = g_dbus_proxy_new_finish (res, &error);
+
+ if (!proxy) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Failed to contact localed: %s\n", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ priv->localed = proxy;
+}
+
+static void
+gis_region_page_constructed (GObject *object)
+{
+ GisRegionPage *page = GIS_REGION_PAGE (object);
+ GisRegionPagePrivate *priv = gis_region_page_get_instance_private (page);
+ GDBusConnection *bus;
+
+ g_type_ensure (CC_TYPE_REGION_CHOOSER);
+
+ G_OBJECT_CLASS (gis_region_page_parent_class)->constructed (object);
+
+ g_signal_connect (priv->region_chooser, "notify::locale",
+ G_CALLBACK (region_changed), page);
+
+ /* If we're in new user mode then we're manipulating system settings */
+ if (gis_driver_get_mode (GIS_PAGE (page)->driver) == GIS_DRIVER_MODE_NEW_USER)
+ {
+ priv->permission = polkit_permission_new_sync ("org.freedesktop.locale1.set-locale", NULL, NULL, NULL);
+
+ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
+ g_dbus_proxy_new (bus,
+ G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
+ NULL,
+ "org.freedesktop.locale1",
+ "/org/freedesktop/locale1",
+ "org.freedesktop.locale1",
+ priv->cancellable,
+ (GAsyncReadyCallback) localed_proxy_ready,
+ object);
+ g_object_unref (bus);
+ }
+
+ gis_page_set_complete (GIS_PAGE (page), TRUE);
+ if (cc_region_chooser_get_n_regions (CC_REGION_CHOOSER (priv->region_chooser)) > 1)
+ gtk_widget_show (GTK_WIDGET (page));
+ else
+ gtk_widget_hide (GTK_WIDGET (page));
+}
+
+static void
+gis_region_page_locale_changed (GisPage *page)
+{
+ GisRegionPagePrivate *priv = gis_region_page_get_instance_private (GIS_REGION_PAGE (page));
+ char *locale;
+
+ gis_page_set_title (page, _("Region"));
+
+ locale = g_strdup (setlocale (LC_MESSAGES, NULL));
+
+ priv->updating = TRUE;
+ cc_region_chooser_set_locale (CC_REGION_CHOOSER (priv->region_chooser), locale);
+ priv->updating = FALSE;
+ g_free (locale);
+
+ if (cc_region_chooser_get_n_regions (CC_REGION_CHOOSER (priv->region_chooser)) > 1)
+ gtk_widget_show (GTK_WIDGET (page));
+ else
+ gtk_widget_hide (GTK_WIDGET (page));
+}
+
+static void
+gis_region_page_dispose (GObject *object)
+{
+ GisRegionPage *page = GIS_REGION_PAGE (object);
+ GisRegionPagePrivate *priv = gis_region_page_get_instance_private (page);
+
+ g_clear_object (&priv->permission);
+ g_clear_object (&priv->localed);
+ g_clear_object (&priv->cancellable);
+
+ G_OBJECT_CLASS (gis_region_page_parent_class)->dispose (object);
+}
+
+static void
+gis_region_page_class_init (GisRegionPageClass *klass)
+{
+ GisPageClass *page_class = GIS_PAGE_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass),
"/org/gnome/initial-setup/gis-region-page.ui");
+
+ gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisRegionPage, region_chooser);
+
+ page_class->page_id = PAGE_ID;
+ page_class->locale_changed = gis_region_page_locale_changed;
+ object_class->constructed = gis_region_page_constructed;
+ object_class->dispose = gis_region_page_dispose;
+}
+
+static void
+gis_region_page_init (GisRegionPage *page)
+{
+ g_resources_register (region_get_resource ());
+ g_type_ensure (CC_TYPE_REGION_CHOOSER);
+
+ gtk_widget_init_template (GTK_WIDGET (page));
+}
+
+void
+gis_prepare_region_page (GisDriver *driver)
+{
+ gis_driver_add_page (driver,
+ g_object_new (GIS_TYPE_REGION_PAGE,
+ "driver", driver,
+ NULL));
+}
diff --git a/gnome-initial-setup/pages/region/gis-region-page.h
b/gnome-initial-setup/pages/region/gis-region-page.h
new file mode 100644
index 0000000..5e7cdea
--- /dev/null
+++ b/gnome-initial-setup/pages/region/gis-region-page.h
@@ -0,0 +1,59 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2013 Red Hat
+ *
+ * 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 <mclasen redhat com>
+ */
+
+#ifndef __GIS_REGION_PAGE_H__
+#define __GIS_REGION_PAGE_H__
+
+#include <glib-object.h>
+
+#include "gnome-initial-setup.h"
+
+G_BEGIN_DECLS
+
+#define GIS_TYPE_REGION_PAGE (gis_region_page_get_type ())
+#define GIS_REGION_PAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GIS_TYPE_REGION_PAGE, GisRegionPage))
+#define GIS_REGION_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GIS_TYPE_REGION_PAGE, GisRegionPageClass))
+#define GIS_IS_REGION_PAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIS_TYPE_REGION_PAGE))
+#define GIS_IS_REGION_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIS_TYPE_REGION_PAGE))
+#define GIS_REGION_PAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GIS_TYPE_REGION_PAGE, GisRegionPageClass))
+
+typedef struct _GisRegionPage GisRegionPage;
+typedef struct _GisRegionPageClass GisRegionPageClass;
+
+struct _GisRegionPage
+{
+ GisPage parent;
+};
+
+struct _GisRegionPageClass
+{
+ GisPageClass parent_class;
+};
+
+GType gis_region_page_get_type (void);
+
+void gis_prepare_region_page (GisDriver *driver);
+
+G_END_DECLS
+
+#endif /* __GIS_REGION_PAGE_H__ */
diff --git a/gnome-initial-setup/pages/region/gis-region-page.ui
b/gnome-initial-setup/pages/region/gis-region-page.ui
new file mode 100644
index 0000000..abfc634
--- /dev/null
+++ b/gnome-initial-setup/pages/region/gis-region-page.ui
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <template class="GisRegionPage" parent="GisPage">
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="visible">True</property>
+ <property name="halign">center</property>
+ <property name="valign">fill</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="pixel_size">96</property>
+ <property name="icon_name">preferences-desktop-locale-symbolic</property>
+ <property name="icon_size">1</property>
+ <property name="margin_top">54</property>
+ <style>
+ <class name="dim-label" />
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="margin_top">26</property>
+ <property name="label" translatable="yes">Region</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="scale" value="1.8"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="margin_top">14</property>
+ <property name="label" translatable="yes">Choose your country or region.</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="max-width-chars">50</property>
+ </object>
+ </child>
+ <child>
+ <object class="CcRegionChooser" id="region_chooser">
+ <property name="margin_top">26</property>
+ <property name="margin_bottom">32</property>
+ <property name="visible">True</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/gnome-initial-setup/pages/region/region-chooser.ui
b/gnome-initial-setup/pages/region/region-chooser.ui
new file mode 100644
index 0000000..f74616e
--- /dev/null
+++ b/gnome-initial-setup/pages/region/region-chooser.ui
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <template class="CcRegionChooser" parent="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolled_window">
+ <property name="visible">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport" id="viewport">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkListBox" 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>
+ </child>
+ <child>
+ <object class="GtkSearchEntry" id="filter_entry">
+ <property name="visible">False</property>
+ <property name="hexpand">True</property>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/gnome-initial-setup/pages/region/region.gresource.xml
b/gnome-initial-setup/pages/region/region.gresource.xml
new file mode 100644
index 0000000..1ed8f38
--- /dev/null
+++ b/gnome-initial-setup/pages/region/region.gresource.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/initial-setup">
+ <file preprocess="xml-stripblanks" alias="gis-region-page.ui">gis-region-page.ui</file>
+ </gresource>
+ <gresource prefix="/org/gnome/control-center">
+ <file preprocess="xml-stripblanks" alias="region-chooser.ui">region-chooser.ui</file>
+ </gresource>
+</gresources>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]