static void theme_changed_on_disk_cb(MateThemeCommonInfo* theme, MateThemeChangeType change_type, MateThemeElement element_type, AppearanceData* data)
{
	if (theme->type == MATE_THEME_TYPE_METATHEME)
	{
		MateThemeMetaInfo* meta = (MateThemeMetaInfo*) theme;

		if (change_type == MATE_THEME_CHANGE_CREATED)
		{
			gtk_list_store_insert_with_values (data->theme_store, NULL, 0, COL_LABEL, meta->readable_name, COL_NAME, meta->name, COL_THUMBNAIL, data->theme_icon, -1);
			theme_thumbnail_generate(meta, data);
		}
		else if (change_type == MATE_THEME_CHANGE_DELETED)
		{
			GtkTreeIter iter;

			if (theme_find_in_model(GTK_TREE_MODEL(data->theme_store), meta->name, &iter))
			{
				gtk_list_store_remove(data->theme_store, &iter);
			}
		}
		else if (change_type == MATE_THEME_CHANGE_CHANGED)
		{
			theme_thumbnail_generate(meta, data);
		}
	}
}
static void theme_thumbnail_update(GdkPixbuf* pixbuf, gchar* theme_name, AppearanceData* data, gboolean cache)
{
	GtkTreeIter iter;
	GtkTreeModel* model = GTK_TREE_MODEL(data->theme_store);

	/* find item in model and update thumbnail */
	if (!pixbuf)
		return;

	if (theme_find_in_model(model, theme_name, &iter))
	{
		time_t mtime;

		gtk_list_store_set(data->theme_store, &iter, COL_THUMBNAIL, pixbuf, -1);

		/* cache thumbnail */
		if (cache && (mtime = theme_get_mtime(theme_name)) != -1)
		{
			gchar* path;

			/* try to share thumbs with caja, use themes:/// */
			path = g_strconcat("themes:///", theme_name, NULL);

			mate_desktop_thumbnail_factory_save_thumbnail(data->thumb_factory, pixbuf, path, mtime);

			g_free(path);
		}
	}
}
static void
theme_select_name (GtkIconView *icon_view, const gchar *theme)
{
  GtkTreeIter iter;
  GtkTreeModel *model = gtk_icon_view_get_model (icon_view);

  if (theme_find_in_model (model, theme, &iter))
    theme_select_iter (icon_view, &iter);
}
static void
save_dialog_response (GtkWidget      *save_dialog,
		      gint            response_id,
		      AppearanceData *data)
{
  if (response_id == GTK_RESPONSE_OK) {
    GtkWidget *entry;
    GtkWidget *text_view;
    GtkTextBuffer *buffer;
    GtkTextIter start_iter;
    GtkTextIter end_iter;
    gchar *buffer_text;
    MateThemeMetaInfo *theme_info;
    gchar *theme_description = NULL;
    gchar *theme_name = NULL;
    gboolean save_background;
    gboolean save_notification;
    GError *error = NULL;

    entry = appearance_capplet_get_widget (data, "save_dialog_entry");
    theme_name = escape_string_and_dup (gtk_entry_get_text (GTK_ENTRY (entry)));

    text_view = appearance_capplet_get_widget (data, "save_dialog_textview");
    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
    gtk_text_buffer_get_start_iter (buffer, &start_iter);
    gtk_text_buffer_get_end_iter (buffer, &end_iter);
    buffer_text = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE);
    theme_description = escape_string_and_dup (buffer_text);
    g_free (buffer_text);
    theme_info = (MateThemeMetaInfo *) g_object_get_data (G_OBJECT (save_dialog), "meta-theme-info");
    save_background = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
		      appearance_capplet_get_widget (data, "save_background_checkbutton")));
    save_notification = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
			appearance_capplet_get_widget (data, "save_notification_checkbutton")));

    if (save_theme_to_disk (theme_info, theme_name, theme_description, save_background, save_notification, &error)) {
      /* remove the custom theme */
      GtkTreeIter iter;

      if (theme_find_in_model (GTK_TREE_MODEL (data->theme_store), "__custom__", &iter))
        gtk_list_store_remove (data->theme_store, &iter);
    }

    g_free (theme_name);
    g_free (theme_description);
    g_clear_error (&error);
  }

  gtk_widget_hide (save_dialog);
}
static void
remove_from_treeview (const gchar *tv_name,
		      const gchar *theme_name,
		      AppearanceData *data)
{
  GtkTreeView *treeview;
  GtkListStore *model;
  GtkTreeIter iter;

  treeview = GTK_TREE_VIEW (appearance_capplet_get_widget (data, tv_name));
  model = GTK_LIST_STORE (
          gtk_tree_model_sort_get_model (
          GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (treeview))));

  if (theme_find_in_model (GTK_TREE_MODEL (model), theme_name, &iter))
    gtk_list_store_remove (model, &iter);
}
static void
update_in_treeview (const gchar *tv_name,
		    const gchar *theme_name,
		    const gchar *theme_label,
		    AppearanceData *data)
{
  GtkTreeView *treeview;
  GtkListStore *model;
  GtkTreeIter iter;

  treeview = GTK_TREE_VIEW (appearance_capplet_get_widget (data, tv_name));
  model = GTK_LIST_STORE (
          gtk_tree_model_sort_get_model (
          GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (treeview))));

  if (theme_find_in_model (GTK_TREE_MODEL (model), theme_name, &iter)) {
    gtk_list_store_set (model, &iter,
          COL_LABEL, theme_label,
          COL_NAME, theme_name,
          -1);
  }
}
static void
update_thumbnail_in_treeview (const gchar *tv_name,
		    const gchar *theme_name,
		    GdkPixbuf *theme_thumbnail,
		    AppearanceData *data)
{
  GtkTreeView *treeview;
  GtkListStore *model;
  GtkTreeIter iter;

  if (theme_thumbnail == NULL)
    return;

  treeview = GTK_TREE_VIEW (appearance_capplet_get_widget (data, tv_name));
  model = GTK_LIST_STORE (
          gtk_tree_model_sort_get_model (
          GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (treeview))));

  if (theme_find_in_model (GTK_TREE_MODEL (model), theme_name, &iter)) {
    gtk_list_store_set (model, &iter,
          COL_THUMBNAIL, theme_thumbnail,
          -1);
  }
}
static void
theme_set_custom_from_theme (const MateThemeMetaInfo *info, AppearanceData *data)
{
  MateThemeMetaInfo *custom = data->theme_custom;
  GtkIconView *icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
  GtkTreeModel *model;
  GtkTreeIter iter;
  GtkTreePath *path;

  if (info == custom)
    return;

  /* if info is not NULL, we'll copy those theme settings over */
  if (info != NULL) {
    g_free (custom->gtk_theme_name);
    g_free (custom->icon_theme_name);
    g_free (custom->marco_theme_name);
    g_free (custom->gtk_color_scheme);
    g_free (custom->cursor_theme_name);
    g_free (custom->application_font);
    custom->gtk_color_scheme = NULL;
    custom->application_font = NULL;

    /* these settings are guaranteed to be non-NULL */
    custom->gtk_theme_name = g_strdup (info->gtk_theme_name);
    custom->icon_theme_name = g_strdup (info->icon_theme_name);
    custom->marco_theme_name = g_strdup (info->marco_theme_name);
    custom->cursor_theme_name = g_strdup (info->cursor_theme_name);
    custom->cursor_size = info->cursor_size;

    /* these can be NULL */
    if (info->gtk_color_scheme)
      custom->gtk_color_scheme = g_strdup (info->gtk_color_scheme);
    else
      custom->gtk_color_scheme = get_default_string_from_key (data->client, COLOR_SCHEME_KEY);

    if (info->application_font)
      custom->application_font = g_strdup (info->application_font);
    else
      custom->application_font = get_default_string_from_key (data->client, APPLICATION_FONT_KEY);
  }

  /* select the custom theme */
  model = gtk_icon_view_get_model (icon_view);
  if (!theme_find_in_model (model, custom->name, &iter)) {
    GtkTreeIter child;

    gtk_list_store_insert_with_values (data->theme_store, &child, 0,
        COL_LABEL, custom->readable_name,
        COL_NAME, custom->name,
        COL_THUMBNAIL, data->theme_icon,
        -1);
    gtk_tree_model_sort_convert_child_iter_to_iter (
        GTK_TREE_MODEL_SORT (model), &iter, &child);
  }

  path = gtk_tree_model_get_path (model, &iter);
  gtk_icon_view_select_path (icon_view, path);
  gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.5, 0.0);
  gtk_tree_path_free (path);

  /* update the theme thumbnail */
  theme_thumbnail_generate (custom, data);
}