[gthumb/ext: 52/79] Execute the gth_file_source_copy operation as a task; Implemented



commit 5b1660bfdaaeb7d2764ef7e0bc6704c33cb3893c
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sat Jul 18 15:26:57 2009 +0200

    Execute the gth_file_source_copy operation as a task; Implemented
    "past into folder" command; Show an error dialog if a background
    task fails;  Added a progress callback to the gth_file_source_copy
    function.

 extensions/catalogs/gth-file-source-catalogs.c |   38 ++++--
 extensions/comments/main.c                     |    4 +-
 extensions/file_manager/Makefile.am            |    2 +
 extensions/file_manager/actions.c              |   79 ++++++------
 extensions/file_manager/gth-copy-task.c        |  170 ++++++++++++++++++++++++
 extensions/file_manager/gth-copy-task.h        |   59 ++++++++
 gthumb/Makefile.am                             |    2 +-
 gthumb/gio-utils.c                             |   72 ++++++++--
 gthumb/gth-browser.c                           |   91 +++++++++++--
 gthumb/gth-file-source-vfs.c                   |   75 ++++++++---
 gthumb/gth-file-source.c                       |   43 ++++---
 gthumb/gth-file-source.h                       |  164 ++++++++++++-----------
 gthumb/typedefs.h                              |   26 +++--
 13 files changed, 611 insertions(+), 214 deletions(-)
---
diff --git a/extensions/catalogs/gth-file-source-catalogs.c b/extensions/catalogs/gth-file-source-catalogs.c
index 561a010..3119747 100644
--- a/extensions/catalogs/gth-file-source-catalogs.c
+++ b/extensions/catalogs/gth-file-source-catalogs.c
@@ -309,9 +309,10 @@ gth_file_source_catalogs_list (GthFileSource *file_source,
 
 typedef struct {
 	GthFileSourceVfs *file_source;
-	GFile            *destination;
+	GthFileData      *destination;
 	GList            *file_list;
-	ReadyCallback     callback;
+	ProgressCallback  progress_callback;
+	ReadyCallback     ready_callback;
 	gpointer          user_data;
 	GList            *files;
 	GthCatalog       *catalog;
@@ -343,11 +344,11 @@ catalog_save_done_cb (void     *buffer,
 
 	if (error == NULL)
 		gth_monitor_folder_changed (gth_main_get_default_monitor (),
-				            cod->destination,
+				            cod->destination->file,
 				            cod->files,
 					    GTH_MONITOR_EVENT_CREATED);
 
-	cod->callback (G_OBJECT (cod->file_source), error, cod->user_data);
+	cod->ready_callback (G_OBJECT (cod->file_source), error, cod->user_data);
 	copy_op_data_free (cod);
 }
 
@@ -362,7 +363,7 @@ catalog_ready_cb (GObject  *catalog,
 	GFile      *gio_file;
 
 	if (error != NULL) {
-		cod->callback (G_OBJECT (cod->file_source), error, cod->user_data);
+		cod->ready_callback (G_OBJECT (cod->file_source), error, cod->user_data);
 		copy_op_data_free (cod);
 		return;
 	}
@@ -373,7 +374,7 @@ catalog_ready_cb (GObject  *catalog,
 		gth_catalog_insert_file (cod->catalog, -1, (GFile *) scan->data);
 
 	cod->buffer = gth_catalog_to_data (cod->catalog, &cod->length);
-	gio_file = gth_catalog_file_to_gio_file (cod->destination);
+	gio_file = gth_catalog_file_to_gio_file (cod->destination->file);
 	g_write_file_async (gio_file,
 			    cod->buffer,
 			    cod->length,
@@ -408,16 +409,17 @@ copy__file_list_info_ready_cb (GList    *files,
 	}
 	cod->files = g_list_reverse (cod->files);
 
-	gth_catalog_load_from_file (cod->destination, catalog_ready_cb, cod);
+	gth_catalog_load_from_file (cod->destination->file, catalog_ready_cb, cod);
 }
 
 
 static void
-gth_file_source_catalogs_copy (GthFileSource *file_source,
-			       GFile         *destination,
-			       GList         *file_list, /* GFile * list */
-			       ReadyCallback  callback,
-			       gpointer       data)
+gth_file_source_catalogs_copy (GthFileSource    *file_source,
+			       GthFileData      *destination,
+			       GList            *file_list, /* GFile * list */
+			       ProgressCallback  progress_callback,
+			       ReadyCallback     ready_callback,
+			       gpointer          data)
 {
 	CopyOpData *cod;
 
@@ -425,9 +427,19 @@ gth_file_source_catalogs_copy (GthFileSource *file_source,
 	cod->file_source = g_object_ref (file_source);
 	cod->destination = g_object_ref (destination);
 	cod->file_list = _g_object_list_ref (file_list);
-	cod->callback = callback;
+	cod->progress_callback = progress_callback;
+	cod->ready_callback = ready_callback;
 	cod->user_data = data;
 
+	if (cod->progress_callback != NULL) {
+		char *message;
+
+		message = g_strdup_printf (_("Copying files to '%s'"), g_file_info_get_display_name (destination->info));
+		(cod->progress_callback) (G_OBJECT (file_source), message, NULL, TRUE, 0.0, cod->user_data);
+
+		g_free (message);
+	}
+
 	g_query_info_async (cod->file_list,
 			    G_FILE_ATTRIBUTE_STANDARD_TYPE,
 			    gth_file_source_get_cancellable (file_source),
diff --git a/extensions/comments/main.c b/extensions/comments/main.c
index e910b06..26832dc 100644
--- a/extensions/comments/main.c
+++ b/extensions/comments/main.c
@@ -40,7 +40,7 @@ GthMetadataInfo comments_metadata_info[] = {
 	{ "comment::note", N_("Comment"), "comment", 1, GTH_METADATA_ALLOW_NOWHERE },
 	{ "comment::place", N_("Place"), "comment", 2, GTH_METADATA_ALLOW_EVERYWHERE },
 	{ "comment::time", N_("Date"), "comment", 3, GTH_METADATA_ALLOW_EVERYWHERE },
-	{ "comment::categories", N_("Categories"), "comment", 4, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
+	{ "comment::categories", N_("Tags"), "comment", 4, GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW },
 	{ "comment::rating", N_("Rating"), "comment", 5, GTH_METADATA_ALLOW_EVERYWHERE },
 	{ NULL, NULL, NULL, 0, 0 }
 };
@@ -100,7 +100,7 @@ gthumb_extension_activate (void)
 				NULL);
 	gth_main_register_test ("comment::category",
 				GTH_TYPE_TEST_CATEGORY,
-				"display-name", _("Category"),
+				"display-name", _("Tag"),
 				NULL);
 	gth_hook_add_callback ("add-sidecars", 10, G_CALLBACK (comments__add_sidecars_cb), NULL);
 }
diff --git a/extensions/file_manager/Makefile.am b/extensions/file_manager/Makefile.am
index 5d4bce8..dc81cec 100644
--- a/extensions/file_manager/Makefile.am
+++ b/extensions/file_manager/Makefile.am
@@ -6,6 +6,8 @@ libfile_manager_la_SOURCES = 		\
 	actions.h			\
 	callbacks.c			\
 	callbacks.h			\
+	gth-copy-task.c			\
+	gth-copy-task.h			\
 	gth-duplicate-task.c		\
 	gth-duplicate-task.h		\
 	main.c
diff --git a/extensions/file_manager/actions.c b/extensions/file_manager/actions.c
index 81bf525..cad0793 100644
--- a/extensions/file_manager/actions.c
+++ b/extensions/file_manager/actions.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #include <glib/gi18n.h>
 #include <gthumb.h>
+#include "gth-copy-task.h"
 #include "gth-duplicate-task.h"
 
 
@@ -246,7 +247,7 @@ gth_browser_activate_action_edit_copy_files (GtkAction  *action,
 
 typedef struct {
 	GthBrowser    *browser;
-	GFile         *destination;
+	GthFileData   *destination;
 	GthFileSource *file_source;
 	GList         *files;
 	gboolean       cut;
@@ -265,57 +266,30 @@ paste_data_free (PasteData *paste_data)
 
 
 static void
-paste_done_cb (GObject  *object,
-	       GError   *error,
-	       gpointer  user_data)
-{
-	PasteData  *paste_data = user_data;
-	GthBrowser *browser = paste_data->browser;
-
-	if (error != NULL) {
-		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not copy the files"), &error);
-		paste_data_free (paste_data);
-		return;
-	}
-
-	if (paste_data->cut) {
-		if (! _g_delete_files (paste_data->files, TRUE, &error))
-			_gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not delete the files"), &error);
-	}
-
-	paste_data_free (paste_data);
-}
-
-
-static void
 clipboard_received_cb (GtkClipboard     *clipboard,
 		       GtkSelectionData *selection_data,
 		       gpointer          user_data)
 {
-	GthBrowser  *browser = user_data;
+	PasteData   *paste_data = user_data;
+	GthBrowser  *browser = paste_data->browser;
 	char       **clipboard_data;
-	PasteData   *paste_data;
 	int          i;
-
+	GthTask     *task;
 
 	clipboard_data = g_strsplit_set ((const char *) gtk_selection_data_get_data (selection_data), "\n\r", -1);
 	if (clipboard_data[0] == NULL) {
 		g_strfreev (clipboard_data);
+		paste_data_free (paste_data);
 		return;
 	}
 
-	paste_data = g_new0 (PasteData, 1);
-	paste_data->browser = g_object_ref (browser);
-	paste_data->destination = g_object_ref (gth_browser_get_location (browser));
 	paste_data->cut = strcmp (clipboard_data[0], "cut") == 0;
-
 	paste_data->files = NULL;
 	for (i = 1; clipboard_data[i] != NULL; i++)
 		if (strcmp (clipboard_data[i], "") != 0)
 			paste_data->files = g_list_prepend (paste_data->files, g_file_new_for_uri (clipboard_data[i]));
 	paste_data->files = g_list_reverse (paste_data->files);
-
-	paste_data->file_source = gth_main_get_file_source (gth_browser_get_location (browser));
+	paste_data->file_source = gth_main_get_file_source (paste_data->destination->file);
 
 	if (paste_data->cut && ! gth_file_source_can_cut (paste_data->file_source)) {
 		GtkWidget *dialog;
@@ -340,11 +314,14 @@ clipboard_received_cb (GtkClipboard     *clipboard,
 		paste_data->cut = FALSE;
 	}
 
-	gth_file_source_copy (paste_data->file_source,
-			      paste_data->destination,
-			      paste_data->files,
-			      paste_done_cb,
-			      paste_data);
+	task = gth_copy_task_new (paste_data->file_source,
+				  paste_data->destination,
+				  paste_data->cut,
+				  paste_data->files);
+	gth_browser_exec_task (browser, task, FALSE);
+
+	g_object_unref (task);
+	paste_data_free (paste_data);
 }
 
 
@@ -352,10 +329,16 @@ void
 gth_browser_activate_action_edit_paste (GtkAction  *action,
 					GthBrowser *browser)
 {
+	PasteData *paste_data;
+
+	paste_data = g_new0 (PasteData, 1);
+	paste_data->browser = g_object_ref (browser);
+	paste_data->destination = g_object_ref (gth_browser_get_location (browser));
+
 	gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (browser), GDK_SELECTION_CLIPBOARD),
 					GNOME_COPIED_FILES,
 					clipboard_received_cb,
-					browser);
+					paste_data);
 }
 
 
@@ -576,7 +559,7 @@ gth_browser_activate_action_folder_copy (GtkAction  *action,
 	file_list = g_list_prepend (NULL, file_data);
 	_gth_browser_clipboard_copy_or_cut (browser, file_list, FALSE);
 
-	g_list_free (file_list);
+	_g_object_list_unref (file_list);
 }
 
 
@@ -584,7 +567,23 @@ void
 gth_browser_activate_action_folder_paste (GtkAction  *action,
 					  GthBrowser *browser)
 {
+	GthFileData *file_data;
+	PasteData   *paste_data;
 
+	file_data = gth_folder_tree_get_selected (GTH_FOLDER_TREE (gth_browser_get_folder_tree (browser)));
+	if (file_data == NULL)
+		return;
+
+	paste_data = g_new0 (PasteData, 1);
+	paste_data->browser = g_object_ref (browser);
+	paste_data->destination = gth_file_data_dup (file_data);
+
+	gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (browser), GDK_SELECTION_CLIPBOARD),
+					GNOME_COPIED_FILES,
+					clipboard_received_cb,
+					paste_data);
+
+	g_object_unref (file_data);
 }
 
 
diff --git a/extensions/file_manager/gth-copy-task.c b/extensions/file_manager/gth-copy-task.c
new file mode 100644
index 0000000..61a1251
--- /dev/null
+++ b/extensions/file_manager/gth-copy-task.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, 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 Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include "gth-copy-task.h"
+
+
+struct _GthCopyTaskPrivate {
+	GthFileData   *destination;
+	GthFileSource *file_source;
+	GList         *files;
+	gboolean       move;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+static void
+gth_copy_task_finalize (GObject *object)
+{
+	GthCopyTask *self;
+
+	self = GTH_COPY_TASK (object);
+
+	_g_object_list_unref (self->priv->files);
+	_g_object_unref (self->priv->file_source);
+	_g_object_unref (self->priv->destination);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+copy_done_cb (GObject    *object,
+	      GError     *error,
+	      gpointer    user_data)
+{
+	gth_task_completed (GTH_TASK (user_data), error);
+}
+
+
+static void
+copy_progress_cb (GObject    *object,
+		  const char *description,
+		  const char *details,
+		  gboolean    pulse,
+		  double      fraction,
+	   	  gpointer    user_data)
+{
+	GthCopyTask *self = user_data;
+
+	gth_task_progress (GTH_TASK (self), description, details, pulse, fraction);
+}
+
+
+static void
+gth_copy_task_exec (GthTask *task)
+{
+	GthCopyTask *self;
+
+	g_return_if_fail (GTH_IS_COPY_TASK (task));
+
+	self = GTH_COPY_TASK (task);
+
+	gth_file_source_copy (self->priv->file_source,
+			      self->priv->destination,
+			      self->priv->files,
+			      copy_progress_cb,
+			      copy_done_cb,
+			      self);
+}
+
+
+static void
+gth_copy_task_cancel (GthTask *task)
+{
+	gth_file_source_cancel (GTH_COPY_TASK (task)->priv->file_source);
+}
+
+
+static void
+gth_copy_task_class_init (GthCopyTaskClass *klass)
+{
+	GObjectClass *object_class;
+	GthTaskClass *task_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthCopyTaskPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gth_copy_task_finalize;
+
+	task_class = GTH_TASK_CLASS (klass);
+	task_class->exec = gth_copy_task_exec;
+	task_class->cancel = gth_copy_task_cancel;
+}
+
+
+static void
+gth_copy_task_init (GthCopyTask *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_COPY_TASK, GthCopyTaskPrivate);
+}
+
+
+GType
+gth_copy_task_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthCopyTaskClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_copy_task_class_init,
+			NULL,
+			NULL,
+			sizeof (GthCopyTask),
+			0,
+			(GInstanceInitFunc) gth_copy_task_init
+		};
+
+		type = g_type_register_static (GTH_TYPE_TASK,
+					       "GthCopyTask",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+GthTask *
+gth_copy_task_new (GthFileSource *file_source,
+		   GthFileData   *destination,
+		   gboolean       move,
+		   GList         *files)
+{
+	GthCopyTask *self;
+
+	self = GTH_COPY_TASK (g_object_new (GTH_TYPE_COPY_TASK, NULL));
+
+	self->priv->file_source = g_object_ref (file_source);
+	self->priv->destination = g_object_ref (destination);
+	self->priv->move = move;
+	self->priv->files = _g_object_list_ref (files);
+
+	return (GthTask *) self;
+}
diff --git a/extensions/file_manager/gth-copy-task.h b/extensions/file_manager/gth-copy-task.h
new file mode 100644
index 0000000..5836ef1
--- /dev/null
+++ b/extensions/file_manager/gth-copy-task.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 The Free Software Foundation, 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 Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_COPY_TASK_H
+#define GTH_COPY_TASK_H
+
+#include <glib.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_COPY_TASK            (gth_copy_task_get_type ())
+#define GTH_COPY_TASK(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_COPY_TASK, GthCopyTask))
+#define GTH_COPY_TASK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_COPY_TASK, GthCopyTaskClass))
+#define GTH_IS_COPY_TASK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_COPY_TASK))
+#define GTH_IS_COPY_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_COPY_TASK))
+#define GTH_COPY_TASK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_COPY_TASK, GthCopyTaskClass))
+
+typedef struct _GthCopyTask        GthCopyTask;
+typedef struct _GthCopyTaskClass   GthCopyTaskClass;
+typedef struct _GthCopyTaskPrivate GthCopyTaskPrivate;
+
+struct _GthCopyTask {
+	GthTask __parent;
+	GthCopyTaskPrivate *priv;
+};
+
+struct _GthCopyTaskClass {
+	GthTaskClass __parent;
+};
+
+GType         gth_copy_task_get_type     (void);
+GthTask *     gth_copy_task_new          (GthFileSource *file_source,
+					  GthFileData   *destination,
+					  gboolean       move,
+					  GList         *file_list);
+
+G_END_DECLS
+
+#endif /* GTH_COPY_TASK_H */
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index e884c6d..f415f7f 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -272,7 +272,7 @@ gth-marshal.h: gth-marshal.list $(GLIB_GENMARSHAL)
 
 gth-marshal.c: gth-marshal.h gth-marshal.list $(GLIB_GENMARSHAL)
 	echo "#include \"gth-marshal.h\"" > $@ \
-	&& $(GLIB_GENMARSHAL) $(srcdir)/gth-marshal.list --body --prefix=gth_marshal >> $@
+	&& $(GLIB_GENMARSHAL) $(srcdir)/gth-marshal.list --body --prefix=gth_marshal >> $@ 
 
 gthumb.h: make-header.sh gthumb.h.template Makefile.am
 	$(srcdir)/make-header.sh $(srcdir)/gthumb.h.template  $(PUBLIC_HEADER_FILES) > xgen-$(@F) \
diff --git a/gthumb/gio-utils.c b/gthumb/gio-utils.c
index 71cf240..a2998b7 100644
--- a/gthumb/gio-utils.c
+++ b/gthumb/gio-utils.c
@@ -1218,12 +1218,11 @@ g_directory_copy_done (gpointer user_data)
 {
 	DirectoryCopyData *dcd = user_data;
 
-	g_source_remove (dcd->source_id);
+	if (dcd->source_id != 0)
+		g_source_remove (dcd->source_id);
 
 	if (dcd->callback)
 		dcd->callback (dcd->error, dcd->user_data);
-	if (dcd->error != NULL)
-		g_clear_error (&(dcd->error));
 	directory_copy_data_free (dcd);
 
 	return FALSE;
@@ -1250,7 +1249,6 @@ get_destination_for_file (DirectoryCopyData *dcd,
 	destination_file = _g_file_append_path (dcd->destination, path);
 
 	g_free (path);
-	g_free (partial_uri);
 	g_free (source_uri);
 	g_free (uri);
 
@@ -1279,7 +1277,7 @@ g_directory_copy_next_child (gpointer user_data)
 static void
 g_directory_copy_child_done_cb (GObject      *source_object,
 				GAsyncResult *result,
-				 gpointer      user_data)
+				 gpointer     user_data)
 {
 	DirectoryCopyData *dcd = user_data;
 
@@ -1457,6 +1455,52 @@ g_directory_copy_start_dir (GFile      *directory,
 }
 
 
+static void
+g_directory_copy_qdestination_info_ready_cb (GObject      *source_object,
+                                             GAsyncResult *result,
+                                             gpointer      user_data)
+{
+	DirectoryCopyData *dcd = user_data;
+	GFileInfo         *info;
+
+	info = g_file_query_info_finish (G_FILE (source_object), result, &dcd->error);
+	if (info == NULL) {
+		if (! g_error_matches (dcd->error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+			g_directory_copy_done (dcd);
+			return;
+		}
+	}
+
+	g_clear_error (&dcd->error);
+
+	if ((info != NULL) && (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY)) {
+		dcd->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, "");
+		g_directory_copy_done (dcd);
+		return;
+	}
+
+	if (! g_file_make_directory (dcd->destination,
+			             dcd->cancellable,
+			             &dcd->error))
+	{
+		g_directory_copy_done (dcd);
+		return;
+	}
+
+	g_clear_error (&dcd->error);
+
+	g_directory_foreach_child (dcd->source,
+				   TRUE,
+				   TRUE,
+				   "standard::name,standard::type",
+				   dcd->cancellable,
+				   g_directory_copy_start_dir,
+				   g_directory_copy_for_each_file,
+				   g_directory_copy_list_ready,
+				   dcd);
+}
+
+
 void
 g_directory_copy_async (GFile                 *source,
 			GFile                 *destination,
@@ -1475,21 +1519,19 @@ g_directory_copy_async (GFile                 *source,
 	dcd->destination = g_file_dup (destination);
 	dcd->flags = flags;
 	dcd->io_priority = io_priority;
-	dcd->cancellable = cancellable;
+	dcd->cancellable = g_object_ref (cancellable);
 	dcd->progress_callback = progress_callback;
 	dcd->progress_callback_data = progress_callback_data;
 	dcd->callback = callback;
 	dcd->user_data = user_data;
 
-	g_directory_foreach_child (dcd->source,
-				   TRUE,
-				   TRUE,
-				   "standard::name,standard::type",
-				   dcd->cancellable,
-				   g_directory_copy_start_dir,
-				   g_directory_copy_for_each_file,
-				   g_directory_copy_list_ready,
-				   dcd);
+	g_file_query_info_async (dcd->destination,
+				 "standard::name,standard::type",
+				 0,
+				 G_PRIORITY_DEFAULT,
+				 dcd->cancellable,
+				 g_directory_copy_qdestination_info_ready_cb,
+				 dcd);
 }
 
 
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index 630a1c8..afd03a5 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -144,6 +144,7 @@ struct _GthBrowserPrivateData {
 	GthTask           *task;
 	gulong             task_completed;
 	gulong             task_progress;
+	GList             *background_tasks;
 	GList             *load_data_queue;
 	guint              load_file_timeout;
 	char              *list_attributes;
@@ -1654,6 +1655,9 @@ _gth_browser_close (GthWindow *window)
 {
 	GthBrowser *browser = (GthBrowser *) window;
 
+	if (browser->priv->background_tasks != NULL)
+		return;
+
 	if (gth_browser_get_file_modified (browser))
 		_gth_browser_ask_whether_to_save (browser,
 						  close__file_saved_cb,
@@ -3312,10 +3316,67 @@ gth_browser_reload (GthBrowser *browser)
 }
 
 
+typedef struct {
+	GthBrowser *browser;
+	GthTask    *task;
+	gulong      completed_event;
+} TaskData;
+
+
+static void
+task_data_free (TaskData *task_data)
+{
+	g_object_unref (task_data->task);
+	g_object_unref (task_data->browser);
+	g_free (task_data);
+}
+
+
+static void
+background_task_completed_cb (GthTask  *task,
+			      GError   *error,
+			      gpointer  user_data)
+{
+	TaskData   *task_data = user_data;
+	GthBrowser *browser = task_data->browser;
+
+	browser->priv->background_tasks = g_list_remove (browser->priv->background_tasks, task_data);
+	task_data_free (task_data);
+
+	if (browser->priv->closing)
+		return;
+
+	if (error == NULL)
+		return;
+
+	if (! g_error_matches (error, GTH_TASK_ERROR, GTH_TASK_ERROR_CANCELLED))
+		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not perform the operation"), &error);
+	else
+		g_error_free (error);
+}
+
+
+static TaskData *
+task_data_new (GthBrowser *browser,
+	       GthTask    *task)
+{
+	TaskData *task_data;
+
+	task_data = g_new0 (TaskData, 1);
+	task_data->browser = g_object_ref (browser);
+	task_data->task = g_object_ref (task);
+	task_data->completed_event = g_signal_connect (task_data->task,
+						       "completed",
+						       G_CALLBACK (background_task_completed_cb),
+						       task_data);
+	return task_data;
+}
+
+
 static void
-task_completed_cb (GthTask    *task,
-		   GError     *error,
-		   GthBrowser *browser)
+foreground_task_completed_cb (GthTask    *task,
+			      GError     *error,
+			      GthBrowser *browser)
 {
 	browser->priv->activity_ref--;
 
@@ -3327,7 +3388,7 @@ task_completed_cb (GthTask    *task,
 		gth_browser_update_sensitivity (browser);
 		if (error != NULL) {
 			if (! g_error_matches (error, GTH_TASK_ERROR, GTH_TASK_ERROR_CANCELLED))
-				_gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not perfom the operation"), &error);
+				_gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not perform the operation"), &error);
 			else
 				g_error_free (error);
 		}
@@ -3342,12 +3403,12 @@ task_completed_cb (GthTask    *task,
 
 
 static void
-task_progress_cb (GthTask    *task,
-		  const char *description,
-		  const char *details,
-		  gboolean    pulse,
-		  double      fraction,
-		  GthBrowser *browser)
+foreground_task_progress_cb (GthTask    *task,
+			     const char *description,
+			     const char *details,
+			     gboolean    pulse,
+			     double      fraction,
+			     GthBrowser *browser)
 {
 	gth_statusbar_set_progress (GTH_STATUSBAR (browser->priv->statusbar), description, pulse, fraction);
 }
@@ -3361,11 +3422,17 @@ gth_browser_exec_task (GthBrowser *browser,
 	g_return_if_fail (task != NULL);
 
 	if (! foreground) {
+		TaskData *task_data;
+
+		task_data = task_data_new (browser, task);
+		browser->priv->background_tasks = g_list_prepend (browser->priv->background_tasks, task_data);
+
 		if (browser->priv->progress_dialog == NULL) {
 			browser->priv->progress_dialog = gth_progress_dialog_new (GTK_WINDOW (browser));
 			g_object_add_weak_pointer (G_OBJECT (browser->priv->progress_dialog), (gpointer*) &(browser->priv->progress_dialog));
 		}
 		gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (browser->priv->progress_dialog), task);
+
 		return;
 	}
 
@@ -3377,11 +3444,11 @@ gth_browser_exec_task (GthBrowser *browser,
 	browser->priv->task = g_object_ref (task);
 	browser->priv->task_completed = g_signal_connect (task,
 							  "completed",
-							  G_CALLBACK (task_completed_cb),
+							  G_CALLBACK (foreground_task_completed_cb),
 							  browser);
 	browser->priv->task_progress = g_signal_connect (task,
 							 "progress",
-							 G_CALLBACK (task_progress_cb),
+							 G_CALLBACK (foreground_task_progress_cb),
 							 browser);
 	browser->priv->activity_ref++;
 	gth_browser_update_sensitivity (browser);
diff --git a/gthumb/gth-file-source-vfs.c b/gthumb/gth-file-source-vfs.c
index 898968b..626cced 100644
--- a/gthumb/gth-file-source-vfs.c
+++ b/gthumb/gth-file-source-vfs.c
@@ -240,13 +240,15 @@ gth_file_source_vfs_list (GthFileSource *file_source,
 
 typedef struct {
 	GthFileSourceVfs *file_source;
-	GFile            *destination;
+	GthFileData      *destination;
 	GList            *file_list;
-	ReadyCallback     callback;
+	ProgressCallback  progress_callback;
+	ReadyCallback     ready_callback;
 	gpointer          user_data;
 	GList            *files;
 	GList            *dirs;
 	GList            *current_dir;
+	char             *message;
 } CopyOpData;
 
 
@@ -258,6 +260,7 @@ copy_op_data_free (CopyOpData *cod)
 	_g_object_list_unref (cod->file_list);
 	_g_object_list_unref (cod->files);
 	_g_object_list_unref (cod->dirs);
+	g_free (cod->message);
 	g_free (cod);
 }
 
@@ -268,7 +271,7 @@ copy__copy_files_done (GError   *error,
 {
 	CopyOpData *cod = user_data;
 
-	cod->callback (G_OBJECT (cod->file_source), error, cod->user_data);
+	cod->ready_callback (G_OBJECT (cod->file_source), error, cod->user_data);
 	copy_op_data_free (cod);
 }
 
@@ -285,7 +288,7 @@ copy__copy_files (CopyOpData *cod)
 		char  *source_basename;
 
 		source_basename = g_file_get_basename (source);
-		destinations = g_list_prepend (destinations, g_file_get_child (cod->destination, source_basename));
+		destinations = g_list_prepend (destinations, g_file_get_child (cod->destination->file, source_basename));
 
 		g_free (source_basename);
 	}
@@ -314,7 +317,7 @@ copy__copy_current_dir_done (GError   *error,
 	CopyOpData *cod = user_data;
 
 	if (error != NULL) {
-		cod->callback (G_OBJECT (cod->file_source), error, cod->user_data);
+		cod->ready_callback (G_OBJECT (cod->file_source), error, cod->user_data);
 		copy_op_data_free (cod);
 		return;
 	}
@@ -325,28 +328,52 @@ copy__copy_current_dir_done (GError   *error,
 
 
 static void
+copy__copy_current_dir_progress (goffset   current_file,
+                                 goffset   total_files,
+                                 GFile    *source,
+                                 GFile    *destination,
+                                 goffset   current_num_bytes,
+                                 goffset   total_num_bytes,
+                                 gpointer  user_data)
+{
+	CopyOpData  *cod = user_data;
+	GthFileData *source_file_data;
+	char        *details;
+
+	if (cod->progress_callback == NULL)
+		return;
+
+	source_file_data = (GthFileData *) cod->current_dir->data;
+	details = g_strdup_printf (_("Copying files from '%s'"), g_file_info_get_display_name (source_file_data->info));
+	(cod->progress_callback) (G_OBJECT (cod->file_source), cod->message, details, FALSE, ((double) current_num_bytes) / total_num_bytes, cod->user_data);
+
+	g_free (details);
+}
+
+
+static void
 copy__copy_current_dir (CopyOpData *cod)
 {
-	GFile *source;
-	char  *source_basename;
-	GFile *destination;
+	GthFileData *source;
+	char        *source_basename;
+	GFile       *destination;
 
 	if (cod->current_dir == NULL) {
 		copy__copy_files (cod);
 		return;
 	}
 
-	source = (GFile *) cod->current_dir->data;
-	source_basename = g_file_get_basename (source);
-	destination = g_file_get_child (cod->destination, source_basename);
+	source = (GthFileData *) cod->current_dir->data;
+	source_basename = g_file_get_basename (source->file);
+	destination = g_file_get_child (cod->destination->file, source_basename);
 
-	g_directory_copy_async (source,
+	g_directory_copy_async (source->file,
 				destination,
 				G_FILE_COPY_NONE,
 				G_PRIORITY_DEFAULT,
 				gth_file_source_get_cancellable (GTH_FILE_SOURCE (cod->file_source)),
-				NULL,
-				NULL,
+				copy__copy_current_dir_progress,
+				cod,
 				copy__copy_current_dir_done,
 				cod);
 
@@ -368,7 +395,7 @@ copy__file_list_info_ready_cb (GList    *files,
 
 		switch (g_file_info_get_file_type (file_data->info)) {
 		case G_FILE_TYPE_DIRECTORY:
-			cod->dirs = g_list_prepend (cod->dirs, g_object_ref (file_data->file));
+			cod->dirs = g_list_prepend (cod->dirs, g_object_ref (file_data));
 			break;
 		case G_FILE_TYPE_REGULAR:
 		case G_FILE_TYPE_SYMBOLIC_LINK:
@@ -387,11 +414,12 @@ copy__file_list_info_ready_cb (GList    *files,
 
 
 static void
-gth_file_source_vfs_copy (GthFileSource *file_source,
-			  GFile         *destination,
-			  GList         *file_list, /* GFile * list */
-			  ReadyCallback  callback,
-			  gpointer       data)
+gth_file_source_vfs_copy (GthFileSource    *file_source,
+			  GthFileData      *destination,
+			  GList            *file_list, /* GFile * list */
+			  ProgressCallback  progress_callback,
+		          ReadyCallback     ready_callback,
+			  gpointer          data)
 {
 	CopyOpData *cod;
 
@@ -399,8 +427,13 @@ gth_file_source_vfs_copy (GthFileSource *file_source,
 	cod->file_source = g_object_ref (file_source);
 	cod->destination = g_object_ref (destination);
 	cod->file_list = _g_object_list_ref (file_list);
-	cod->callback = callback;
+	cod->progress_callback = progress_callback;
+	cod->ready_callback = ready_callback;
 	cod->user_data = data;
+	cod->message = g_strdup_printf (_("Copying files to '%s'"), g_file_info_get_display_name (destination->info));
+
+	if (cod->progress_callback != NULL)
+		(cod->progress_callback) (G_OBJECT (file_source), cod->message, _("Getting files information"), TRUE, 0.0, cod->user_data);
 
 	g_query_info_async (cod->file_list,
 			    G_FILE_ATTRIBUTE_STANDARD_TYPE,
diff --git a/gthumb/gth-file-source.c b/gthumb/gth-file-source.c
index 79be24d..92bcc59 100644
--- a/gthumb/gth-file-source.c
+++ b/gthumb/gth-file-source.c
@@ -79,10 +79,11 @@ typedef struct {
 
 
 typedef struct {
-	GFile         *destination;
-	GList         *file_list;
-	ReadyCallback  callback;
-	gpointer       data;
+	GthFileData      *destination;
+	GList            *file_list;
+	ProgressCallback  progress_callback;
+	ReadyCallback     ready_callback;
+	gpointer          data;
 } CopyData;
 
 
@@ -186,20 +187,22 @@ gth_file_source_queue_rename (GthFileSource *file_source,
 
 
 static void
-gth_file_source_queue_copy (GthFileSource *file_source,
-			    GFile          *destination,
-			    GList          *file_list,
-			    ReadyCallback   callback,
-			    gpointer        data)
+gth_file_source_queue_copy (GthFileSource    *file_source,
+			    GthFileData      *destination,
+			    GList            *file_list,
+			    ProgressCallback  progress_callback,
+			    ReadyCallback     ready_callback,
+			    gpointer          data)
 {
 	FileSourceAsyncOp *async_op;
 
 	async_op = g_new0 (FileSourceAsyncOp, 1);
 	async_op->file_source = file_source;
 	async_op->op = FILE_SOURCE_OP_COPY;
-	async_op->data.copy.destination = g_file_dup (destination);
+	async_op->data.copy.destination = gth_file_data_dup (destination);
 	async_op->data.copy.file_list = _g_file_list_dup (file_list);
-	async_op->data.copy.callback = callback;
+	async_op->data.copy.progress_callback = progress_callback;
+	async_op->data.copy.ready_callback = ready_callback;
 	async_op->data.copy.data = data;
 
 	file_source->priv->queue = g_list_append (file_source->priv->queue, async_op);
@@ -245,7 +248,8 @@ gth_file_source_exec_next_in_queue (GthFileSource *file_source)
 		gth_file_source_copy (file_source,
 				      async_op->data.copy.destination,
 				      async_op->data.copy.file_list,
-				      async_op->data.copy.callback,
+				      async_op->data.copy.progress_callback,
+				      async_op->data.copy.ready_callback,
 				      async_op->data.copy.data);
 		break;
 	}
@@ -685,17 +689,18 @@ gth_file_source_rename (GthFileSource  *file_source,
 
 
 void
-gth_file_source_copy (GthFileSource  *file_source,
-		      GFile          *destination,
-		      GList          *file_list, /* GFile * list */
-		      ReadyCallback   callback,
-		      gpointer        data)
+gth_file_source_copy (GthFileSource    *file_source,
+		      GthFileData      *destination,
+		      GList            *file_list, /* GFile * list */
+		      ProgressCallback  progress_callback,
+		      ReadyCallback     ready_callback,
+		      gpointer          data)
 {
 	if (gth_file_source_is_active (file_source)) {
-		gth_file_source_queue_copy (file_source, destination, file_list, callback, data);
+		gth_file_source_queue_copy (file_source, destination, file_list, progress_callback, ready_callback, data);
 		return;
 	}
-	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->copy (file_source, destination, file_list, callback, data);
+	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->copy (file_source, destination, file_list, progress_callback, ready_callback, data);
 }
 
 
diff --git a/gthumb/gth-file-source.h b/gthumb/gth-file-source.h
index 3a9d7b1..55cf866 100644
--- a/gthumb/gth-file-source.h
+++ b/gthumb/gth-file-source.h
@@ -65,93 +65,95 @@ struct _GthFileSourceClass
 
 	/*< virtual functions >*/
 
-	GList *      (*get_entry_points)      (GthFileSource  *file_source);
-	GList *      (*get_current_list)      (GthFileSource  *file_source,
-					       GFile          *file);
-	GFile *      (*to_gio_file)           (GthFileSource  *file_source,
-					       GFile          *file);
-	GFileInfo *  (*get_file_info)         (GthFileSource  *file_source,
-					       GFile          *file,
-					       const char     *attributes);
-	GthFileData *(*get_file_data)         (GthFileSource  *file_source,
-					       GFile          *file,
-					       GFileInfo      *info);
-	void         (*list)                  (GthFileSource  *file_source,
-					       GFile          *folder,
-					       const char     *attributes,
-					       ListReady       func,
-					       gpointer        data);
-	void         (*rename)                (GthFileSource  *file_source,
-					       GFile          *file,
-					       GFile          *new_file,
-					       ReadyCallback   callback,
-					       gpointer        data);
-	void         (*copy)                  (GthFileSource  *file_source,
-					       GFile          *destination,
-					       GList          *file_list, /* GFile * list */
-					       ReadyCallback   callback,
-					       gpointer        data);
-	gboolean     (*can_cut)               (GthFileSource  *file_source);
-	void         (*monitor_entry_points)  (GthFileSource  *file_source);
-	void         (*monitor_directory)     (GthFileSource  *file_source,
-					       GFile          *file,
-					       gboolean        activate);
+	GList *      (*get_entry_points)      (GthFileSource    *file_source);
+	GList *      (*get_current_list)      (GthFileSource    *file_source,
+					       GFile            *file);
+	GFile *      (*to_gio_file)           (GthFileSource    *file_source,
+					       GFile            *file);
+	GFileInfo *  (*get_file_info)         (GthFileSource    *file_source,
+					       GFile            *file,
+					       const char       *attributes);
+	GthFileData *(*get_file_data)         (GthFileSource    *file_source,
+					       GFile            *file,
+					       GFileInfo        *info);
+	void         (*list)                  (GthFileSource    *file_source,
+					       GFile            *folder,
+					       const char       *attributes,
+					       ListReady         func,
+					       gpointer          data);
+	void         (*rename)                (GthFileSource    *file_source,
+					       GFile            *file,
+					       GFile            *new_file,
+					       ReadyCallback     callback,
+					       gpointer          data);
+	void         (*copy)                  (GthFileSource    *file_source,
+					       GthFileData      *destination,
+					       GList            *file_list, /* GFile * list */
+					       ProgressCallback  progress_callback,
+					       ReadyCallback     callback,
+					       gpointer          data);
+	gboolean     (*can_cut)               (GthFileSource    *file_source);
+	void         (*monitor_entry_points)  (GthFileSource    *file_source);
+	void         (*monitor_directory)     (GthFileSource    *file_source,
+					       GFile            *file,
+					       gboolean          activate);
 };
 
-GType        gth_file_source_get_type              (void) G_GNUC_CONST;
+GType          gth_file_source_get_type              (void) G_GNUC_CONST;
 
-/*< protected >*/
+/*< public >*/
 
-void         gth_file_source_add_scheme            (GthFileSource  *file_source,
-						    const char     *scheme);
-gboolean     gth_file_source_supports_scheme       (GthFileSource  *file_source,
-						    const char     *uri);
-void         gth_file_source_set_active            (GthFileSource  *file_source,
-						    gboolean        pending);
+GList *        gth_file_source_get_entry_points      (GthFileSource    *file_source); /* GthFileData list */
+GList *        gth_file_source_get_current_list      (GthFileSource    *file_source,  /* GFile list */
+						      GFile            *file);
+GFile *        gth_file_source_to_gio_file           (GthFileSource    *file_source,
+						      GFile            *file);
+GList *        gth_file_source_to_gio_file_list      (GthFileSource    *file_source,
+						      GList            *files);
+GFileInfo *    gth_file_source_get_file_info         (GthFileSource    *file_source,
+						      GFile            *file,
+						      const char       *attributes);
+GthFileData *  gth_file_source_get_file_data         (GthFileSource    *file_source,
+					              GFile            *file,
+					              GFileInfo        *info);
+gboolean       gth_file_source_is_active             (GthFileSource    *file_source);
+void           gth_file_source_cancel                (GthFileSource    *file_source);
+void           gth_file_source_list                  (GthFileSource    *file_source,
+						      GFile            *folder,
+						      const char       *attributes,
+						      ListReady         func,
+						      gpointer          data);
+void           gth_file_source_read_attributes       (GthFileSource    *file_source,
+						      GList            *files,
+						      const char       *attributes,
+						      ListReady         func,
+						      gpointer          data);
+void           gth_file_source_rename                (GthFileSource    *file_source,
+						      GFile            *file,
+						      GFile            *new_file,
+						      ReadyCallback     ready_cb,
+						      gpointer          data);
+void           gth_file_source_copy                  (GthFileSource    *file_source,
+						      GthFileData      *destination,
+						      GList            *file_list, /* GFile list */
+						      ProgressCallback  progress_callback,
+						      ReadyCallback     ready_callback,
+						      gpointer          data);
+gboolean       gth_file_source_can_cut               (GthFileSource    *file_source);
+void           gth_file_source_monitor_entry_points  (GthFileSource    *file_source);
+void           gth_file_source_monitor_directory     (GthFileSource    *file_source,
+						      GFile            *file,
+						      gboolean          activate);
 
-/*< public >*/
+/*< protected >*/
 
-GList *      gth_file_source_get_entry_points      (GthFileSource  *file_source); /* GthFileData list */
-GList *      gth_file_source_get_current_list      (GthFileSource  *file_source,  /* GFile list */
-						    GFile          *file);
-GFile *      gth_file_source_to_gio_file           (GthFileSource  *file_source,
-						    GFile          *file);
-GList *      gth_file_source_to_gio_file_list      (GthFileSource  *file_source,
-						    GList          *files);
-GFileInfo *  gth_file_source_get_file_info         (GthFileSource  *file_source,
-						    GFile          *file,
-						    const char     *attributes);
-GthFileData *gth_file_source_get_file_data         (GthFileSource  *file_source,
-					            GFile          *file,
-					            GFileInfo      *info);
-gboolean     gth_file_source_is_active             (GthFileSource  *file_source);
-GCancellable *gth_file_source_get_cancellable      (GthFileSource  *file_source);
-void         gth_file_source_cancel                (GthFileSource  *file_source);
-void         gth_file_source_list                  (GthFileSource  *file_source,
-						    GFile          *folder,
-						    const char     *attributes,
-						    ListReady       func,
-						    gpointer        data);
-void         gth_file_source_read_attributes       (GthFileSource  *file_source,
-						    GList          *files,
-						    const char     *attributes,
-						    ListReady       func,
-						    gpointer        data);
-void         gth_file_source_rename                (GthFileSource  *file_source,
-						    GFile          *file,
-						    GFile          *new_file,
-						    ReadyCallback   callback,
-						    gpointer        data);
-void         gth_file_source_copy                  (GthFileSource  *file_source,
-						    GFile          *destination,
-						    GList          *file_list, /* GFile list */
-						    ReadyCallback   callback,
-						    gpointer        data);
-gboolean     gth_file_source_can_cut               (GthFileSource  *file_source);
-void         gth_file_source_monitor_entry_points  (GthFileSource  *file_source);
-void         gth_file_source_monitor_directory     (GthFileSource  *file_source,
-						    GFile          *file,
-						    gboolean        activate);
+void           gth_file_source_add_scheme            (GthFileSource  *file_source,
+						      const char     *scheme);
+gboolean       gth_file_source_supports_scheme       (GthFileSource  *file_source,
+						      const char     *uri);
+void           gth_file_source_set_active            (GthFileSource  *file_source,
+						      gboolean        pending);
+GCancellable * gth_file_source_get_cancellable       (GthFileSource  *file_source);
 
 G_END_DECLS
 
diff --git a/gthumb/typedefs.h b/gthumb/typedefs.h
index 3f297e7..1ef0975 100644
--- a/gthumb/typedefs.h
+++ b/gthumb/typedefs.h
@@ -37,9 +37,9 @@ G_BEGIN_DECLS
 #define RC_REMOTE_CACHE_DIR       ".gnome2/gthumb/remote_cache"
 */
 
-#define BOOKMARKS_FILE    "bookmarks.xbel"
-#define FILTERS_FILE      "filters.xml"
-#define FILE_CACHE        "cache"
+#define BOOKMARKS_FILE "bookmarks.xbel"
+#define FILTERS_FILE   "filters.xml"
+#define FILE_CACHE     "cache"
 
 
 typedef enum {
@@ -86,13 +86,19 @@ typedef enum {
 } GthTransform;
 
 
-typedef void (*ErrorFunc)      (gpointer  user_data);
-typedef void (*DoneFunc)       (gpointer  user_data);
-typedef void (*ReadyFunc)      (GError   *error,
-				gpointer  user_data);
-typedef void (*ReadyCallback)  (GObject  *object,
-				GError   *error,
-			   	gpointer  user_data);
+typedef void (*ErrorFunc)        (gpointer    user_data);
+typedef void (*DoneFunc)         (gpointer    user_data);
+typedef void (*ReadyFunc)        (GError     *error,
+			 	  gpointer    user_data);
+typedef void (*ReadyCallback)    (GObject    *object,
+				  GError     *error,
+			   	  gpointer    user_data);
+typedef void (*ProgressCallback) (GObject    *object,
+				  const char *description,
+				  const char *details,
+			          gboolean    pulse,
+			          double      fraction,
+			   	  gpointer    user_data);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]