summaryrefslogtreecommitdiff
path: root/capplets/appearance/theme-installer.c
diff options
context:
space:
mode:
Diffstat (limited to 'capplets/appearance/theme-installer.c')
-rw-r--r--capplets/appearance/theme-installer.c801
1 files changed, 801 insertions, 0 deletions
diff --git a/capplets/appearance/theme-installer.c b/capplets/appearance/theme-installer.c
new file mode 100644
index 00000000..fec1f001
--- /dev/null
+++ b/capplets/appearance/theme-installer.c
@@ -0,0 +1,801 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+#include "appearance.h"
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+#include <unistd.h>
+
+#include "capplet-util.h"
+#include "file-transfer-dialog.h"
+#include "theme-installer.h"
+#include "theme-util.h"
+
+enum {
+ THEME_INVALID,
+ THEME_ICON,
+ THEME_MATE,
+ THEME_GTK,
+ THEME_ENGINE,
+ THEME_MARCO,
+ THEME_CURSOR,
+ THEME_ICON_CURSOR
+};
+
+enum {
+ TARGZ,
+ TARBZ,
+ DIRECTORY
+};
+
+static gboolean
+cleanup_tmp_dir (GIOSchedulerJob *job,
+ GCancellable *cancellable,
+ const gchar *tmp_dir)
+{
+ GFile *directory;
+
+ directory = g_file_new_for_path (tmp_dir);
+ capplet_file_delete_recursive (directory, NULL);
+ g_object_unref (directory);
+
+ return FALSE;
+}
+
+static int
+file_theme_type (const gchar *dir)
+{
+ gchar *filename = NULL;
+ gboolean exists;
+
+ if (!dir)
+ return THEME_INVALID;
+
+ filename = g_build_filename (dir, "index.theme", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
+
+ if (exists) {
+ GPatternSpec *pattern;
+ gchar *file_contents = NULL;
+ gsize file_size;
+ gboolean match;
+
+ g_file_get_contents (filename, &file_contents, &file_size, NULL);
+ g_free (filename);
+
+ pattern = g_pattern_spec_new ("*[Icon Theme]*");
+ match = g_pattern_match_string (pattern, file_contents);
+ g_pattern_spec_free (pattern);
+
+ if (match) {
+ pattern = g_pattern_spec_new ("*Directories=*");
+ match = g_pattern_match_string (pattern, file_contents);
+ g_pattern_spec_free (pattern);
+ g_free (file_contents);
+
+ if (match) {
+ /* check if we have a cursor, too */
+ filename = g_build_filename (dir, "cursors", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
+ g_free (filename);
+
+ if (exists)
+ return THEME_ICON_CURSOR;
+ else
+ return THEME_ICON;
+ }
+ return THEME_CURSOR;
+ }
+
+ pattern = g_pattern_spec_new ("*[X-GNOME-Metatheme]*");
+ match = g_pattern_match_string (pattern, file_contents);
+ g_pattern_spec_free (pattern);
+ g_free (file_contents);
+
+ if (match)
+ return THEME_MATE;
+ } else {
+ g_free (filename);
+ }
+
+ filename = g_build_filename (dir, "gtk-2.0", "gtkrc", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
+ g_free (filename);
+
+ if (exists)
+ return THEME_GTK;
+
+ filename = g_build_filename (dir, "metacity-1", "metacity-theme-1.xml", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
+ g_free (filename);
+
+ if (exists)
+ return THEME_MARCO;
+
+ /* cursor themes don't necessarily have an index.theme */
+ filename = g_build_filename (dir, "cursors", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
+ g_free (filename);
+
+ if (exists)
+ return THEME_CURSOR;
+
+ filename = g_build_filename (dir, "configure", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE);
+ g_free (filename);
+
+ if (exists)
+ return THEME_ENGINE;
+
+ return THEME_INVALID;
+}
+
+static void
+transfer_cancel_cb (GtkWidget *dialog,
+ gchar *path)
+{
+ GFile *todelete;
+
+ todelete = g_file_new_for_path (path);
+ capplet_file_delete_recursive (todelete, NULL);
+
+ g_object_unref (todelete);
+ g_free (path);
+ gtk_widget_destroy (dialog);
+}
+
+static void
+missing_utility_message_dialog (GtkWindow *parent,
+ const gchar *utility)
+{
+ GtkWidget *dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Cannot install theme"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("The %s utility is not installed."), utility);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+/* this works around problems when doing fork/exec in a threaded app
+ * with some locks being held/waited on in different threads.
+ *
+ * we do the idle callback so that the async xfer has finished and
+ * cleaned up its vfs job. otherwise it seems the slave thread gets
+ * woken up and it removes itself from the job queue before it is
+ * supposed to. very strange.
+ *
+ * see bugzilla.gnome.org #86141 for details
+ */
+static gboolean
+process_local_theme_tgz_tbz (GtkWindow *parent,
+ const gchar *util,
+ const gchar *tmp_dir,
+ const gchar *archive)
+{
+ gboolean rc;
+ int status;
+ gchar *command, *filename, *zip, *tar;
+
+ if (!(zip = g_find_program_in_path (util))) {
+ missing_utility_message_dialog (parent, util);
+ return FALSE;
+ }
+ if (!(tar = g_find_program_in_path ("tar"))) {
+ missing_utility_message_dialog (parent, "tar");
+ g_free (zip);
+ return FALSE;
+ }
+
+ filename = g_shell_quote (archive);
+
+ /* this should be something more clever and nonblocking */
+ command = g_strdup_printf ("sh -c 'cd \"%s\"; %s -d -c < \"%s\" | %s xf - '",
+ tmp_dir, zip, filename, tar);
+ g_free (zip);
+ g_free (tar);
+ g_free (filename);
+
+ rc = (g_spawn_command_line_sync (command, NULL, NULL, &status, NULL) && status == 0);
+ g_free (command);
+
+ if (rc == FALSE) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Cannot install theme"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("There was a problem while extracting the theme."));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+
+ return rc;
+}
+
+static gboolean
+process_local_theme_archive (GtkWindow *parent,
+ gint filetype,
+ const gchar *tmp_dir,
+ const gchar *archive)
+{
+ if (filetype == TARGZ)
+ return process_local_theme_tgz_tbz (parent, "gzip", tmp_dir, archive);
+ else if (filetype == TARBZ)
+ return process_local_theme_tgz_tbz (parent, "bzip2", tmp_dir, archive);
+ else
+ return FALSE;
+}
+
+static void
+invalid_theme_dialog (GtkWindow *parent,
+ const gchar *filename,
+ gboolean maybe_theme_engine)
+{
+ GtkWidget *dialog;
+ const gchar *primary = _("There was an error installing the selected file");
+ const gchar *secondary = _("\"%s\" does not appear to be a valid theme.");
+ const gchar *engine = _("\"%s\" does not appear to be a valid theme. It may be a theme engine which you need to compile.");
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s", primary);
+ if (maybe_theme_engine)
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), engine, filename);
+ else
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), secondary, filename);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static gboolean
+mate_theme_install_real (GtkWindow *parent,
+ gint filetype,
+ const gchar *tmp_dir,
+ const gchar *theme_name,
+ gboolean ask_user)
+{
+ gboolean success = TRUE;
+ GtkWidget *dialog, *apply_button;
+ GFile *theme_source_dir, *theme_dest_dir;
+ GError *error = NULL;
+ gint theme_type;
+ gchar *target_dir = NULL;
+
+ /* What type of theme is it? */
+ theme_type = file_theme_type (tmp_dir);
+ switch (theme_type) {
+ case THEME_ICON:
+ case THEME_CURSOR:
+ case THEME_ICON_CURSOR:
+ target_dir = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (), ".icons",
+ theme_name, NULL);
+ break;
+ case THEME_MATE:
+ target_dir = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (), ".themes",
+ theme_name, NULL);
+ break;
+ case THEME_MARCO:
+ case THEME_GTK:
+ target_dir = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (), ".themes",
+ theme_name, NULL);
+ break;
+ case THEME_ENGINE:
+ invalid_theme_dialog (parent, theme_name, TRUE);
+ return FALSE;
+ default:
+ invalid_theme_dialog (parent, theme_name, FALSE);
+ return FALSE;
+ }
+
+ /* see if there is an icon theme lurking in this package */
+ if (theme_type == THEME_MATE) {
+ gchar *path;
+
+ path = g_build_path (G_DIR_SEPARATOR_S,
+ tmp_dir, "icons", NULL);
+ if (g_file_test (path, G_FILE_TEST_IS_DIR)
+ && (file_theme_type (path) == THEME_ICON)) {
+ gchar *new_path, *update_icon_cache;
+ GFile *new_file;
+ GFile *src_file;
+
+ src_file = g_file_new_for_path (path);
+ new_path = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (),
+ ".icons",
+ theme_name, NULL);
+ new_file = g_file_new_for_path (new_path);
+
+ if (!g_file_move (src_file, new_file, G_FILE_COPY_NONE,
+ NULL, NULL, NULL, &error)) {
+ g_warning ("Error while moving from `%s' to `%s': %s",
+ path, new_path, error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ g_object_unref (new_file);
+ g_object_unref (src_file);
+
+ /* update icon cache - shouldn't really matter if this fails */
+ update_icon_cache = g_strdup_printf ("gtk-update-icon-cache %s", new_path);
+ g_spawn_command_line_async (update_icon_cache, NULL);
+ g_free (update_icon_cache);
+
+ g_free (new_path);
+ }
+ g_free (path);
+ }
+
+ /* Move the dir to the target dir */
+ theme_source_dir = g_file_new_for_path (tmp_dir);
+ theme_dest_dir = g_file_new_for_path (target_dir);
+
+ if (!g_file_move (theme_source_dir, theme_dest_dir,
+ G_FILE_COPY_OVERWRITE, NULL, NULL,
+ NULL, &error)) {
+ gchar *str;
+
+ str = g_strdup_printf (_("Installation for theme \"%s\" failed."), theme_name);
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s",
+ str);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", error->message);
+
+ g_free (str);
+ g_error_free (error);
+ error = NULL;
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ success = FALSE;
+ } else {
+ if (theme_type == THEME_ICON || theme_type == THEME_ICON_CURSOR)
+ {
+ gchar *update_icon_cache;
+
+ /* update icon cache - shouldn't really matter if this fails */
+ update_icon_cache = g_strdup_printf ("gtk-update-icon-cache %s", target_dir);
+ g_spawn_command_line_async (update_icon_cache, NULL);
+
+ g_free (update_icon_cache);
+ }
+
+ if (ask_user) {
+ /* Ask to apply theme (if we can) */
+ if (theme_type == THEME_GTK
+ || theme_type == THEME_MARCO
+ || theme_type == THEME_ICON
+ || theme_type == THEME_CURSOR
+ || theme_type == THEME_ICON_CURSOR) {
+ /* TODO: currently cannot apply "mate themes" */
+ gchar *str;
+
+ str = g_strdup_printf (_("The theme \"%s\" has been installed."), theme_name);
+ dialog = gtk_message_dialog_new_with_markup (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_NONE,
+ "<span weight=\"bold\" size=\"larger\">%s</span>",
+ str);
+ g_free (str);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("Would you like to apply it now, or keep your current theme?"));
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("Keep Current Theme"),
+ GTK_RESPONSE_CLOSE);
+
+ apply_button = gtk_button_new_with_label (_("Apply New Theme"));
+ gtk_button_set_image (GTK_BUTTON (apply_button),
+ gtk_image_new_from_stock (GTK_STOCK_APPLY,
+ GTK_ICON_SIZE_BUTTON));
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), apply_button, GTK_RESPONSE_APPLY);
+ gtk_widget_set_can_default (apply_button, TRUE);
+ gtk_widget_show (apply_button);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_APPLY);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_APPLY) {
+ /* apply theme here! */
+ MateConfClient *mateconf_client;
+
+ mateconf_client = mateconf_client_get_default ();
+
+ switch (theme_type) {
+ case THEME_GTK:
+ mateconf_client_set_string (mateconf_client, GTK_THEME_KEY, theme_name, NULL);
+ break;
+ case THEME_MARCO:
+ mateconf_client_set_string (mateconf_client, MARCO_THEME_KEY, theme_name, NULL);
+ break;
+ case THEME_ICON:
+ mateconf_client_set_string (mateconf_client, ICON_THEME_KEY, theme_name, NULL);
+ break;
+ case THEME_CURSOR:
+ mateconf_client_set_string (mateconf_client, CURSOR_THEME_KEY, theme_name, NULL);
+ break;
+ case THEME_ICON_CURSOR:
+ mateconf_client_set_string (mateconf_client, ICON_THEME_KEY, theme_name, NULL);
+ mateconf_client_set_string (mateconf_client, CURSOR_THEME_KEY, theme_name, NULL);
+ break;
+ default:
+ break;
+ }
+
+ g_object_unref (mateconf_client);
+ }
+ } else {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ _("MATE Theme %s correctly installed"),
+ theme_name);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ }
+ gtk_widget_destroy (dialog);
+ }
+ }
+
+ g_free (target_dir);
+
+ return success;
+}
+
+static void
+process_local_theme (GtkWindow *parent,
+ const char *path)
+{
+ GtkWidget *dialog;
+ gint filetype;
+
+ if (g_str_has_suffix (path, ".tar.gz")
+ || g_str_has_suffix (path, ".tgz")
+ || g_str_has_suffix(path, ".gtp")) {
+ filetype = TARGZ;
+ } else if (g_str_has_suffix (path, ".tar.bz2")) {
+ filetype = TARBZ;
+ } else if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
+ filetype = DIRECTORY;
+ } else {
+ gchar *filename;
+ filename = g_path_get_basename (path);
+ invalid_theme_dialog (parent, filename, FALSE);
+ g_free (filename);
+ return;
+ }
+
+ if (filetype == DIRECTORY) {
+ gchar *name = g_path_get_basename (path);
+ mate_theme_install_real (parent,
+ filetype,
+ path,
+ name,
+ TRUE);
+ g_free (name);
+ } else {
+ /* Create a temp directory and uncompress file there */
+ GDir *dir;
+ const gchar *name;
+ gchar *tmp_dir;
+ gboolean ok;
+ gint n_themes;
+ GFile *todelete;
+
+ tmp_dir = g_strdup_printf ("%s/.themes/.theme-%u",
+ g_get_home_dir (),
+ g_random_int ());
+
+ if ((g_mkdir (tmp_dir, 0700)) != 0) {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Failed to create temporary directory"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_free (tmp_dir);
+ return;
+ }
+
+ if (!process_local_theme_archive (parent, filetype, tmp_dir, path)
+ || ((dir = g_dir_open (tmp_dir, 0, NULL)) == NULL)) {
+ g_io_scheduler_push_job ((GIOSchedulerJobFunc) cleanup_tmp_dir,
+ g_strdup (tmp_dir),
+ g_free,
+ G_PRIORITY_DEFAULT,
+ NULL);
+ g_free (tmp_dir);
+ return;
+ }
+
+ todelete = g_file_new_for_path (path);
+ g_file_delete (todelete, NULL, NULL);
+ g_object_unref (todelete);
+
+ /* See whether we have multiple themes to install. If so,
+ * we won't ask the user whether to apply the new theme
+ * after installation. */
+ n_themes = 0;
+ for (name = g_dir_read_name (dir);
+ name && n_themes <= 1;
+ name = g_dir_read_name (dir)) {
+ gchar *theme_dir;
+
+ theme_dir = g_build_filename (tmp_dir, name, NULL);
+
+ if (g_file_test (theme_dir, G_FILE_TEST_IS_DIR))
+ ++n_themes;
+
+ g_free (theme_dir);
+ }
+ g_dir_rewind (dir);
+
+ ok = TRUE;
+ for (name = g_dir_read_name (dir); name && ok;
+ name = g_dir_read_name (dir)) {
+ gchar *theme_dir;
+
+ theme_dir = g_build_filename (tmp_dir, name, NULL);
+
+ if (g_file_test (theme_dir, G_FILE_TEST_IS_DIR))
+ ok = mate_theme_install_real (parent,
+ filetype,
+ theme_dir,
+ name,
+ n_themes == 1);
+
+ g_free (theme_dir);
+ }
+ g_dir_close (dir);
+
+ if (ok && n_themes > 1) {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ _("New themes have been successfully installed."));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+ g_io_scheduler_push_job ((GIOSchedulerJobFunc) cleanup_tmp_dir,
+ tmp_dir, g_free,
+ G_PRIORITY_DEFAULT, NULL);
+ }
+}
+
+typedef struct
+{
+ GtkWindow *parent;
+ char *path;
+} TransferData;
+
+static void
+transfer_done_cb (GtkWidget *dialog,
+ TransferData *tdata)
+{
+ gdk_threads_enter ();
+ /* XXX: path should be on the local filesystem by now? */
+
+ if (dialog != NULL) {
+ gtk_widget_destroy (dialog);
+ }
+
+ process_local_theme (tdata->parent, tdata->path);
+
+ g_free (tdata->path);
+ g_free (tdata);
+
+ gdk_threads_leave ();
+}
+
+void
+mate_theme_install (GFile *file,
+ GtkWindow *parent)
+{
+ GtkWidget *dialog;
+ gchar *path, *base;
+ GList *src, *target;
+ const gchar *template;
+ TransferData *tdata;
+
+ if (file == NULL) {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("No theme file location specified to install"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ return;
+ }
+
+ /* see if someone dropped a local directory */
+ if (g_file_is_native (file)
+ && g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL) == G_FILE_TYPE_DIRECTORY) {
+ path = g_file_get_path (file);
+ process_local_theme (parent, path);
+ g_free (path);
+ return;
+ }
+
+ /* we can't tell if this is an icon theme yet, so just make a
+ * temporary copy in .themes */
+ path = g_build_filename (g_get_home_dir (), ".themes", NULL);
+
+ if (access (path, X_OK | W_OK) != 0) {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Insufficient permissions to install the theme in:\n%s"), path);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_free (path);
+ return;
+ }
+
+ base = g_file_get_basename (file);
+
+ if (g_str_has_suffix (base, ".tar.gz")
+ || g_str_has_suffix (base, ".tgz")
+ || g_str_has_suffix (base, ".gtp"))
+ template = "mate-theme-%d.gtp";
+ else if (g_str_has_suffix (base, ".tar.bz2"))
+ template = "mate-theme-%d.tar.bz2";
+ else {
+ invalid_theme_dialog (parent, base, FALSE);
+ g_free (base);
+ return;
+ }
+ g_free (base);
+
+ src = g_list_append (NULL, g_object_ref (file));
+
+ path = NULL;
+ do {
+ gchar *file_tmp;
+
+ g_free (path);
+ file_tmp = g_strdup_printf (template, g_random_int ());
+ path = g_build_filename (g_get_home_dir (), ".themes", file_tmp, NULL);
+ g_free (file_tmp);
+ } while (g_file_test (path, G_FILE_TEST_EXISTS));
+
+ tdata = g_new0 (TransferData, 1);
+ tdata->parent = parent;
+ tdata->path = path;
+
+ dialog = file_transfer_dialog_new_with_parent (parent);
+ g_signal_connect (dialog,
+ "cancel",
+ (GCallback) transfer_cancel_cb, path);
+ g_signal_connect (dialog,
+ "done",
+ (GCallback) transfer_done_cb, tdata);
+
+ target = g_list_append (NULL, g_file_new_for_path (path));
+ file_transfer_dialog_copy_async (FILE_TRANSFER_DIALOG (dialog),
+ src,
+ target,
+ FILE_TRANSFER_DIALOG_DEFAULT,
+ G_PRIORITY_DEFAULT);
+ gtk_widget_show (dialog);
+
+ /* don't free the path since we're using that for the signals */
+ g_list_foreach (src, (GFunc) g_object_unref, NULL);
+ g_list_free (src);
+ g_list_foreach (target, (GFunc) g_object_unref, NULL);
+ g_list_free (target);
+}
+
+void
+mate_theme_installer_run (GtkWindow *parent,
+ const gchar *filename)
+{
+ static gboolean running_theme_install = FALSE;
+ static gchar old_folder[512] = "";
+ GtkWidget *dialog;
+ GtkFileFilter *filter;
+
+ if (running_theme_install)
+ return;
+
+ running_theme_install = TRUE;
+
+ if (filename == NULL)
+ filename = old_folder;
+
+ dialog = gtk_file_chooser_dialog_new (_("Select Theme"),
+ parent,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT,
+ GTK_STOCK_OPEN,
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("Theme Packages"));
+ gtk_file_filter_add_mime_type (filter, "application/x-bzip-compressed-tar");
+ gtk_file_filter_add_mime_type (filter, "application/x-compressed-tar");
+ gtk_file_filter_add_mime_type (filter, "application/x-mate-theme-package");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("All Files"));
+ gtk_file_filter_add_pattern(filter, "*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+ if (strcmp (old_folder, ""))
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), old_folder);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ gchar *uri_selected, *folder;
+
+ uri_selected = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+
+ folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
+ g_strlcpy (old_folder, folder, 255);
+ g_free (folder);
+
+ gtk_widget_destroy (dialog);
+
+ if (uri_selected != NULL) {
+ GFile *file = g_file_new_for_uri (uri_selected);
+ g_free (uri_selected);
+
+ mate_theme_install (file, parent);
+ g_object_unref (file);
+ }
+ } else {
+ gtk_widget_destroy (dialog);
+ }
+
+ /*
+ * we're relying on the mate theme info module to pick up changes
+ * to the themes so we don't need to update the model here
+ */
+
+ running_theme_install = FALSE;
+}