GHashTable *
cc_common_language_get_initial_regions (const gchar *lang)
{
        GHashTable *ht;
        char *language;
        gchar **langs;
        gint i;

        ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);

        /* Add some common regions */
        g_hash_table_insert (ht, g_strdup ("en_US.utf8"), g_strdup (_("United States")));
        g_hash_table_insert (ht, g_strdup ("de_DE.utf8"), g_strdup (_("Germany")));
        g_hash_table_insert (ht, g_strdup ("fr_FR.utf8"), g_strdup (_("France")));
        g_hash_table_insert (ht, g_strdup ("es_ES.utf8"), g_strdup (_("Spain")));
        g_hash_table_insert (ht, g_strdup ("zh_CN.utf8"), g_strdup (_("China")));

        gdm_parse_language_name (lang, &language, NULL, NULL, NULL);
        langs = gdm_get_all_language_names ();
        for (i = 0; langs[i]; i++) {
                gchar *l, *s;
                gdm_parse_language_name (langs[i], &l, NULL, NULL, NULL);
                if (g_strcmp0 (language, l) == 0) {
                        if (!g_hash_table_lookup (ht, langs[i])) {
                                s = gdm_get_region_from_name (langs[i], NULL);
                                g_hash_table_insert (ht, g_strdup (langs[i]), s);
                        }
                }
                g_free (l);
        }
        g_strfreev (langs);
        g_free (language);

        return ht;
}
static void
populate_regions (GtkBuilder *builder, const gchar *current_lang)
{
        gchar *current_region;
        GSettings *locale_settings;
        GHashTable *ht;
        GHashTableIter htiter;
        GtkTreeModel *model;
        gchar *name, *language;
        GtkWidget *treeview;
        GtkTreeIter iter;
        GtkTreeSelection *selection;

        treeview = GTK_WIDGET (gtk_builder_get_object (builder, "region_selector"));
        /* don't update the setting just because the list is repopulated */
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
        g_signal_handlers_block_by_func (selection, update_settings_cb, builder);

        model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
        locale_settings = g_object_get_data (G_OBJECT (treeview), "settings");

        ht = cc_common_language_get_initial_regions (current_lang);

        current_region = g_settings_get_string (locale_settings, "region");
        if (!current_region || !current_region[0]) {
                current_region = g_strdup (current_lang);
        }
        else if (!g_hash_table_lookup (ht, current_region)) {
                name = gdm_get_region_from_name (current_region, NULL);
                g_hash_table_insert (ht, g_strdup (current_region), name);
        }

        gtk_list_store_clear (GTK_LIST_STORE (model));

        g_hash_table_iter_init (&htiter, ht);
        while (g_hash_table_iter_next (&htiter, (gpointer *)&name, (gpointer *)&language)) {
                gtk_list_store_append (GTK_LIST_STORE (model), &iter);
                gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, name, 1, language, -1);
        }
        g_hash_table_unref (ht);

        select_region (GTK_TREE_VIEW (treeview), current_region);

        g_free (current_region);

        g_signal_handlers_unblock_by_func (selection, update_settings_cb, builder);
}
static gboolean
iter_for_language (GtkTreeModel *model,
                   const gchar  *lang,
                   GtkTreeIter  *iter,
                   gboolean      region)
{
        char *l;
        char *name;
        char *language;

        gtk_tree_model_get_iter_first (model, iter);
        do {
                gtk_tree_model_get (model, iter, LOCALE_COL, &l, -1);
                if (g_strcmp0 (l, lang) == 0) {
                        g_free (l);
                        return TRUE;
                }
                g_free (l);
        } while (gtk_tree_model_iter_next (model, iter));

        name = gdm_normalize_language_name (lang);
        if (name != NULL) {
                if (region) {
                        language = gdm_get_region_from_name (name, NULL);
                }
                else {
                        language = gdm_get_language_from_name (name, NULL);
                }

                gtk_list_store_insert_with_values (GTK_LIST_STORE (model),
                                                   iter,
                                                   -1,
                                                   LOCALE_COL, name,
                                                   DISPLAY_LOCALE_COL, language,
                                                   -1);
                g_free (name);
                g_free (language);
                return TRUE;
        }

        return FALSE;
}
static void
locale_settings_changed (GSettings *settings,
                         const gchar *key,
                         GtkBuilder *dialog)
{
        GtkWidget *label;
        gchar *region, *display_region;

        region = g_settings_get_string (locale_settings, "region");
        if (!region || !region[0]) {
                label = WID ("user_display_language");
                region = g_strdup ((gchar*)g_object_get_data (G_OBJECT (label), "language"));
        }

        display_region = gdm_get_region_from_name (region, NULL);
        label = WID ("user_format");
        gtk_label_set_text (GTK_LABEL (label), display_region);
        g_object_set_data_full (G_OBJECT (label), "region", g_strdup (region), g_free);
        g_free (region);
        g_free (display_region);

        update_copy_button (dialog);
}
static gboolean
add_one_language (gpointer d)
{
  AsyncLangData *data = d;
  char *name;
  char *language;
  GtkTreeIter iter;

  if (data->languages[data->position] == NULL) {
    /* we are done */
    async_lang_data_free (data);
    return FALSE;
  }

  name = gdm_normalize_language_name (data->languages[data->position]);
  if (g_hash_table_lookup (data->user_langs, name) != NULL) {
    g_free (name);
    goto next;
  }

  if (!cc_common_language_has_font (data->languages[data->position])) {
    g_free (name);
    goto next;
  }

  if (data->regions) {
    language = gdm_get_region_from_name (name, NULL);
  }
  else {
    language = gdm_get_language_from_name (name, NULL);
  }
  if (!language) {
    g_debug ("Ignoring '%s' as a locale, because we couldn't figure the language name", name);
    g_free (name);
    goto next;
  }

  /* Add separator between initial languages and new additions */
  if (g_object_get_data (G_OBJECT (data->store), "needs-separator")) {
    GtkTreeIter iter;

    gtk_list_store_insert_with_values (GTK_LIST_STORE (data->store),
                                       &iter,
                                       -1,
                                       LOCALE_COL, NULL,
                                       DISPLAY_LOCALE_COL, "Don't show",
                                       SEPARATOR_COL, TRUE,
                                       USER_LANGUAGE, FALSE,
                                       -1);
    g_object_set_data (G_OBJECT (data->store), "needs-separator", NULL);
  }

  gtk_list_store_insert_with_values (data->store,
                                     &iter,
                                     -1,
                                     LOCALE_COL, name,
                                     DISPLAY_LOCALE_COL, language,
                                     -1);

  g_free (name);
  g_free (language);

 next:
  data->position++;

  return TRUE;
}
static void
on_localed_properties_changed (GDBusProxy   *proxy,
                               GVariant     *changed_properties,
                               const gchar **invalidated_properties,
                               GtkBuilder   *dialog)
{
        GVariant *v;
        GtkWidget *label;
        const char *layout;
        char **layouts;
        GString *disp;
        guint i;

        if (invalidated_properties != NULL) {
                guint i;
                for (i = 0; invalidated_properties[i] != NULL; i++) {
                        if (g_str_equal (invalidated_properties[i], "Locale"))
                                update_property (proxy, "Locale");
                        else if (g_str_equal (invalidated_properties[i], "X11Layout"))
                                update_property (proxy, "X11Layout");
                }
        }

        v = g_dbus_proxy_get_cached_property (proxy, "Locale");
        if (v) {
                const gchar **strv;
                gsize len;
                gint i;
                const gchar *lang, *messages, *time;
                gchar *name;
                GtkWidget *label;

                strv = g_variant_get_strv (v, &len);

                lang = messages = time = NULL;
                for (i = 0; strv[i]; i++) {
                        if (g_str_has_prefix (strv[i], "LANG=")) {
                                lang = strv[i] + strlen ("LANG=");
                        }
                        else if (g_str_has_prefix (strv[i], "LC_MESSAGES=")) {
                                messages = strv[i] + strlen ("LC_MESSAGES=");
                        }
                        else if (g_str_has_prefix (strv[i], "LC_TIME=")) {
                                time = strv[i] + strlen ("LC_TIME=");
                        }
                }
                if (!messages) {
                        messages = lang;
                }
                if (!time) {
                        time = lang;
                }

                if (messages) {
                        name = gdm_get_language_from_name (messages, NULL);
                        label = WID ("system_display_language");
                        gtk_label_set_text (GTK_LABEL (label), name);
                        g_free (name);
                        g_object_set_data_full (G_OBJECT (label), "language", g_strdup (lang), g_free);
                }

                if (time) {
                        name = gdm_get_region_from_name (time, NULL);
                        label = WID ("system_format");
                        gtk_label_set_text (GTK_LABEL (label), name);
                        g_free (name);
                        g_object_set_data_full (G_OBJECT (label), "region", g_strdup (time), g_free);
                }
                g_variant_unref (v);
        }

        label = WID ("system_input_source");
        v = g_dbus_proxy_get_cached_property (proxy, "X11Layout");
        if (v) {
                layout = g_variant_get_string (v, NULL);
                g_object_set_data_full (G_OBJECT (label), "input_source", g_strdup (layout), g_free);
	} else {
                g_object_set_data_full (G_OBJECT (label), "input_source", NULL, g_free);
                update_copy_button (dialog);
                return;
        }

	disp = g_string_new ("");
	layouts = g_strsplit (layout, ",", -1);
	for (i = 0; layouts[i]; i++) {
		gchar *utf_visible;

		utf_visible = xkb_layout_description_utf8 (layouts[i]);
		if (disp->str[0] != '\0')
			disp = g_string_append (disp, ", ");
		disp = g_string_append (disp, utf_visible ? utf_visible : layouts[i]);
		g_free (utf_visible);
	}
        gtk_label_set_text (GTK_LABEL (label), disp->str);
        g_string_free (disp, TRUE);

        g_variant_unref (v);

        update_copy_button (dialog);
}