static void
xkb_settings_changed (GSettings *settings,
                      const gchar *key,
                      GtkBuilder *dialog)
{
	guint i;
	GString *disp, *list, *variants;
	GtkWidget *label;
	gchar **layouts;

	layouts = g_settings_get_strv (settings, "layouts");
	if (layouts == NULL)
		return;

	label = WID ("user_input_source");
	disp = g_string_new ("");
	list = g_string_new ("");
	variants = g_string_new ("");

	for (i = 0; layouts[i]; i++) {
		gchar *utf_visible;
		char **split;
		gchar *layout, *variant;

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

		split = g_strsplit_set (layouts[i], " \t", 2);

		if (split == NULL || split[0] == NULL)
			continue;

		layout = split[0];
		variant = split[1];

		if (list->str[0] != '\0')
			g_string_append (list, ",");
		g_string_append (list, layout);

		if (variants->str[0] != '\0')
			g_string_append (variants, ",");
		g_string_append (variants, variant ? variant : "");

		g_strfreev (split);
	}
	g_strfreev (layouts);

        g_object_set_data_full (G_OBJECT (label), "input_source", g_string_free (list, FALSE), g_free);
        g_object_set_data_full (G_OBJECT (label), "input_variants", g_string_free (variants, FALSE), g_free);
        gtk_label_set_text (GTK_LABEL (label), disp->str);
        g_string_free (disp, TRUE);

	update_copy_button (dialog);
}
void
xkb_layouts_fill_selected_tree (GtkBuilder * dialog)
{
	GSList *layouts = xkb_layouts_get_selected_list ();
	GSList *cur_layout;
	GtkListStore *list_store =
	    GTK_LIST_STORE (gtk_tree_view_get_model
			    (GTK_TREE_VIEW
			     (WID ("xkb_layouts_selected"))));
	int counter = 0;

	/* temporarily disable the buttons' status update */
	disable_buttons_sensibility_update = TRUE;

	gtk_list_store_clear (list_store);

	for (cur_layout = layouts; cur_layout != NULL;
	     cur_layout = cur_layout->next, counter++) {
		GtkTreeIter iter;
		const char *visible = (char *) cur_layout->data;
		gchar *utf_visible = xkb_layout_description_utf8 (visible);
		gtk_list_store_append (list_store, &iter);
		gtk_list_store_set (list_store, &iter,
				    SEL_LAYOUT_TREE_COL_DESCRIPTION,
				    utf_visible,
				    SEL_LAYOUT_TREE_COL_ID,
				    cur_layout->data,
				    SEL_LAYOUT_TREE_COL_ENABLED,
				    counter < max_selected_layouts, -1);
		g_free (utf_visible);
	}

	clear_xkb_elements_list (layouts);

	/* enable the buttons' status update */
	disable_buttons_sensibility_update = FALSE;

	if (idx2select != -1) {
		GtkTreeSelection *selection =
		    gtk_tree_view_get_selection ((GTK_TREE_VIEW
						  (WID
						   ("xkb_layouts_selected"))));
		GtkTreePath *path =
		    gtk_tree_path_new_from_indices (idx2select, -1);
		gtk_tree_selection_select_path (selection, path);
		gtk_tree_path_free (path);
		idx2select = -1;
	} else {
		/* if there is nothing to select - just enable/disable the buttons,
		   otherwise it would be done by the selection change */
		xkb_layouts_enable_disable_buttons (dialog);
	}
}
void
xkb_layouts_fill_selected_tree (GtkBuilder * dialog)
{
	gchar **layouts = xkb_layouts_get_selected_list ();
	guint i;
	GtkListStore *list_store =
	    GTK_LIST_STORE (gtk_tree_view_get_model
			    (GTK_TREE_VIEW
			     (WID ("xkb_layouts_selected"))));

	/* temporarily disable the buttons' status update */
	disable_buttons_sensibility_update = TRUE;

	gtk_list_store_clear (list_store);

	for (i = 0; layouts != NULL && layouts[i] != NULL; i++) {
		char *cur_layout = layouts[i];
		gchar *utf_visible =
		    xkb_layout_description_utf8 (cur_layout);

		gtk_list_store_insert_with_values (list_store, NULL, G_MAXINT,
						   SEL_LAYOUT_TREE_COL_DESCRIPTION,
						   utf_visible,
						   SEL_LAYOUT_TREE_COL_ID,
						   cur_layout,
						   SEL_LAYOUT_TREE_COL_ENABLED,
						   i < max_selected_layouts, -1);
		g_free (utf_visible);
	}

	g_strfreev (layouts);

	/* enable the buttons' status update */
	disable_buttons_sensibility_update = FALSE;

	if (idx2select != -1) {
		GtkTreeSelection *selection =
		    gtk_tree_view_get_selection ((GTK_TREE_VIEW
						  (WID
						   ("xkb_layouts_selected"))));
		GtkTreePath *path =
		    gtk_tree_path_new_from_indices (idx2select, -1);
		gtk_tree_selection_select_path (selection, path);
		gtk_tree_path_free (path);
		idx2select = -1;
	} else {
		/* if there is nothing to select - just enable/disable the buttons,
		   otherwise it would be done by the selection change */
		xkb_layouts_enable_disable_buttons (dialog);
	}
}
static void
show_selected_layout (GtkWidget * button, GtkBuilder * dialog)
{
	gint idx = find_selected_layout_idx (dialog);

	if (idx != -1) {
		GSList *layouts_list = xkb_layouts_get_selected_list ();
		const gchar *id = g_slist_nth_data (layouts_list, idx);
		char *descr = xkb_layout_description_utf8 (id);
		GtkWidget *parent = WID ("keyboard_dialog");
		GtkWidget *popup = matekbd_keyboard_drawing_new_dialog (idx, descr);
		gtk_widget_set_parent (popup, parent);
		clear_xkb_elements_list (layouts_list);
		g_free (descr);
	}
}
static void
xkb_layout_chooser_print (GtkBuilder * chooser_dialog)
{
	GtkWidget *chooser = CWID ("xkb_layout_chooser");
	GtkWidget *kbdraw =
	    GTK_WIDGET (g_object_get_data (G_OBJECT (chooser), "kbdraw"));
	const char *id =
	    xkb_layout_chooser_get_selected_id (chooser_dialog);
	char *descr = xkb_layout_description_utf8 (id);
	matekbd_keyboard_drawing_print (MATEKBD_KEYBOARD_DRAWING
				     (kbdraw),
				     GTK_WINDOW (CWID
						 ("xkb_layout_chooser")),
				     descr);
	g_free (descr);
}
static void
 xkb_layout_chooser_add_variant_to_available_country_variants
    (XklConfigRegistry * config_registry,
     XklConfigItem * parent_config_item, XklConfigItem * config_item,
     AddVariantData * data) {
	gchar *utf_variant_name = config_item ?
	    xkb_layout_description_utf8 (matekbd_keyboard_config_merge_items
					 (parent_config_item->name,
					  config_item->name)) :
	    xci_desc_to_utf8 (parent_config_item);
	GtkTreeIter iter;
	const gchar *xkb_id =
	    config_item ?
	    matekbd_keyboard_config_merge_items (parent_config_item->name,
					      config_item->name) :
	    parent_config_item->name;

	if (config_item && g_object_get_data
	    (G_OBJECT (config_item), XCI_PROP_EXTRA_ITEM)) {
		gchar *buf =
		    g_strdup_printf ("<i>%s</i>", utf_variant_name);
		gtk_list_store_insert_with_values (data->list_store, &iter,
						   -1,
						   COMBO_BOX_MODEL_COL_SORT,
						   utf_variant_name,
						   COMBO_BOX_MODEL_COL_VISIBLE,
						   buf,
						   COMBO_BOX_MODEL_COL_XKB_ID,
						   xkb_id, -1);
		g_free (buf);
	} else
		gtk_list_store_insert_with_values (data->list_store, &iter,
						   -1,
						   COMBO_BOX_MODEL_COL_SORT,
						   utf_variant_name,
						   COMBO_BOX_MODEL_COL_VISIBLE,
						   utf_variant_name,
						   COMBO_BOX_MODEL_COL_XKB_ID,
						   xkb_id, -1);
	g_free (utf_variant_name);
}
static void
chooser_response (GtkDialog  *chooser,
		  int         response_id,
		  GtkBuilder *dialog)
{
	if (response_id == GTK_RESPONSE_OK) {
		char *id, *name;
		GtkListStore *list_store;

		list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("xkb_layouts_selected"))));
		id = xkb_layout_chooser_get_selected_id (chooser);
		name = xkb_layout_description_utf8 (id);
		gtk_list_store_insert_with_values (list_store, NULL, G_MAXINT,
						   SEL_LAYOUT_TREE_COL_DESCRIPTION, name,
						   SEL_LAYOUT_TREE_COL_ID, id,
						   SEL_LAYOUT_TREE_COL_ENABLED, TRUE,
						   -1);
		g_free (name);
		add_default_switcher_if_necessary ();
		update_layouts_list (GTK_TREE_MODEL (list_store), dialog);
	}

	xkb_layout_chooser_response (chooser, response_id);
}
static void
xkl_layout_add_to_list (XklConfigRegistry * config,
			const XklConfigItem * item,
			const XklConfigItem * subitem,
			GtkBuilder * chooser_dialog)
{
	GtkListStore *list_store =
	    GTK_LIST_STORE (gtk_builder_get_object (chooser_dialog,
						    "layout_list_model"));
	GtkTreeIter iter;

	gchar *utf_variant_name =
	    subitem ?
	    xkb_layout_description_utf8 (gkbd_keyboard_config_merge_items
					 (item->name,
					  subitem->name)) :
	    xci_desc_to_utf8 (item);

	const gchar *xkb_id =
	    subitem ? gkbd_keyboard_config_merge_items (item->name,
							subitem->name) :
	    item->name;

	gchar *country_desc =
	    xkl_create_description_from_list (item, subitem,
					      XCI_PROP_COUNTRY_LIST,
					      xkl_get_country_name);
	gchar *language_desc =
	    xkl_create_description_from_list (item, subitem,
					      XCI_PROP_LANGUAGE_LIST,
					      xkl_get_language_name);

	gchar *tmp = utf_variant_name;
	utf_variant_name =
	    g_regex_replace_literal (left_bracket_regex, tmp, -1, 0,
				     "&lt;", 0, NULL);
	g_free (tmp);

	if (subitem
	    && g_object_get_data (G_OBJECT (subitem),
				  XCI_PROP_EXTRA_ITEM)) {
		gchar *buf =
		    g_strdup_printf ("<i>%s</i>", utf_variant_name);
		gtk_list_store_insert_with_values (list_store, &iter, -1,
						   COMBO_BOX_MODEL_COL_SORT,
						   utf_variant_name,
						   COMBO_BOX_MODEL_COL_VISIBLE,
						   buf,
						   COMBO_BOX_MODEL_COL_XKB_ID,
						   xkb_id,
						   COMBO_BOX_MODEL_COL_COUNTRY_DESC,
						   country_desc,
						   COMBO_BOX_MODEL_COL_LANGUAGE_DESC,
						   language_desc, -1);
		g_free (buf);
	} else
		gtk_list_store_insert_with_values (list_store, &iter,
						   -1,
						   COMBO_BOX_MODEL_COL_SORT,
						   utf_variant_name,
						   COMBO_BOX_MODEL_COL_VISIBLE,
						   utf_variant_name,
						   COMBO_BOX_MODEL_COL_XKB_ID,
						   xkb_id,
						   COMBO_BOX_MODEL_COL_COUNTRY_DESC,
						   country_desc,
						   COMBO_BOX_MODEL_COL_LANGUAGE_DESC,
						   language_desc, -1);
	g_free (utf_variant_name);
	g_free (country_desc);
	g_free (language_desc);
}
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);
}