Index: libgthumb/gfile-utils.c
===================================================================
--- libgthumb/gfile-utils.c	(revisão 2394)
+++ libgthumb/gfile-utils.c	(cópia de trabalho)
@@ -32,8 +32,194 @@
  * NOTE: All these functions accept/return _only_ uri-style GFiles.
  */
 
+struct _AsyncXferData {
+	guint                  ref_count;
+	GList                 *source_list;
+	GList                 *destination_list;
+	GFileCopyFlags         flags;
+	GFileProgressCallback  progress_callback;
+	gpointer               progress_data;
+	GDestroyNotify         progress_data_free;
+	AsyncXferEachFileFunc  each_file_callback;
+	gpointer               each_file_data;
+	GCancellable          *cancel;
+	GSourceFunc            done_func;
+	gpointer               done_data;
+	GDestroyNotify         done_free;
+	gboolean               move_files;
+};
 
+struct _AsyncXferEachFile {
+	AsyncXferEachFileFunc  callback;
+	GFile                 *src;
+	GFile                 *dest;
+	GError                *error;
+	AsyncXferData         *data;
+	gpointer               each_file_data;
+};
 
+static AsyncXferData * _async_xfer_data_ref (AsyncXferData *data);
+static void            _async_xfer_data_try_destroy (gpointer data);
+static gboolean        _async_xfer_data_unref (AsyncXferData *data, gboolean try_free);
+static gboolean        _async_xfer_job_do (GIOSchedulerJob *job, GCancellable *cancellable, gpointer user_data);
+
+static AsyncXferData *
+_async_xfer_data_new ()
+{
+	AsyncXferData *data;
+	data = g_new0(AsyncXferData, 1);
+	data->ref_count = 1;
+	data->source_list = NULL;
+	data->destination_list = NULL;
+	data->flags = 0;
+	data->progress_callback = NULL;
+	data->progress_data = NULL;
+	data->progress_data_free = NULL;
+	data->cancel = NULL;
+	data->done_func = NULL;
+	data->done_data = NULL;
+	data->done_free = NULL;
+	data->move_files = FALSE;
+	return data;
+}
+
+static AsyncXferData *
+_async_xfer_data_ref (AsyncXferData *data)
+{
+	data->ref_count++;
+	return data;
+}
+
+static void
+_async_xfer_data_try_destroy (gpointer data)
+{
+	AsyncXferData *axdata = data;
+	_async_xfer_data_unref (axdata, TRUE);
+}
+
+static gboolean
+_async_xfer_data_unref (AsyncXferData *data, gboolean try_free)
+{return;
+	if (data->ref_count > 0)
+		data->ref_count--;
+	else
+		{
+			if (try_free)
+				{
+					g_list_foreach (data->source_list,
+							(GFunc)g_object_unref,
+							NULL);
+					g_list_free (data->source_list);
+					g_list_foreach (data->destination_list,
+							(GFunc)g_object_unref,
+							NULL);
+					g_list_free (data->destination_list);
+					g_object_unref (data->cancel);
+					data->ref_count = 1;
+					data->source_list = NULL;
+					data->destination_list = NULL;
+					data->flags = 0;
+					data->progress_callback = NULL;
+					data->progress_data = NULL;
+					data->progress_data_free = NULL;
+					data->cancel = NULL;
+					data->done_func = NULL;
+					data->done_data = NULL;
+					data->done_free = NULL;
+					data->move_files = FALSE;
+					g_free (data);
+					data = NULL;
+				}
+			return FALSE;
+		}
+	return TRUE;
+}
+
+static gboolean
+_async_xfer_each_file_in_mainloop (gpointer data)
+{
+	AsyncXferEachFile *axef = data;
+	axef->callback 
+		(axef->src,
+		 axef->dest,
+		 axef->error, 
+		 axef->data, 
+		 axef->each_file_data);
+
+	return FALSE;
+}
+
+static gboolean
+_async_xfer_job_do (GIOSchedulerJob *job,
+		    GCancellable *cancellable,
+		    gpointer user_data)
+{
+	AsyncXferData *data = user_data;
+	GFile *src, *dst;
+	GError *error = NULL;
+	guint counter = 0;
+	GList *scan;
+
+	data->source_list = g_list_first(data->source_list);
+	data->destination_list = g_list_first(data->destination_list);
+
+	for(scan = data->source_list; scan != NULL; scan = g_list_next(scan))
+		{
+			if (g_cancellable_is_cancelled (cancellable))
+				return FALSE;
+
+			data->destination_list = g_list_nth (data->destination_list, counter);
+			if ((!data->source_list) || (!data->destination_list))
+				return FALSE;
+
+			src = g_object_ref (scan->data);
+			dst = g_object_ref (data->destination_list->data);
+			g_clear_error (&error);
+
+			if (data->move_files)
+				g_file_move (src, dst, data->flags, cancellable, 
+					     data->progress_callback,
+					     data->progress_data, 
+					     &error);
+			else
+				g_file_copy (src, dst, data->flags, cancellable,
+					     data->progress_callback,
+					     data->progress_data,
+					     &error);
+
+			if (data->each_file_callback)
+				{
+					AsyncXferEachFile *axef = g_new0 (AsyncXferEachFile, 1);
+					axef->callback = data->each_file_callback;
+					axef->src = src;
+					axef->dest = dst;
+					axef->error = error;
+					axef->data = data;
+					axef->each_file_data = data->each_file_data;
+					g_io_scheduler_job_send_to_mainloop (job,
+									     _async_xfer_each_file_in_mainloop, 
+									     axef,
+									     g_free);
+				}
+
+			if (data->done_func)
+				g_io_scheduler_job_send_to_mainloop (job, 
+								     data->done_func,
+								     data->done_data,
+								     data->done_free);
+
+			UNREF (src);
+			UNREF (dst);
+			counter++; /* must be increased here */
+		}
+
+	if (data->progress_data_free)
+		data->progress_data_free (data->progress_data);
+
+
+	return FALSE;
+}
+
 /* GFile to string */
 
 char *
@@ -582,3 +768,52 @@
 {
 	return gfile_xfer (sfile, dfile, TRUE);
 }
+
+void
+async_xfer_file_gio (GList *source_list,
+		     GList *destination_list,
+		     gboolean move_files,
+		     GFileCopyFlags flags, 
+		     GCancellable *cancel,
+		     GFileProgressCallback progress_callback,
+		     gpointer progress_data,
+		     GDestroyNotify progress_data_free,
+		     AsyncXferEachFileFunc each_file_callback,
+		     gpointer each_file_data,
+		     gint io_priority,
+		     GSourceFunc done_func,
+		     gpointer done_data,
+		     GDestroyNotify done_free)
+{
+	GList *scan;
+	AsyncXferData *data;
+
+	g_assert (g_list_length (source_list) == g_list_length (destination_list));
+
+	data = _async_xfer_data_new ();
+	data->source_list = NULL;
+	data->destination_list = NULL;
+	for (scan = source_list; scan != NULL; scan = g_list_next(scan))
+		data->source_list = g_list_prepend(data->source_list,
+						   g_object_ref (G_FILE (scan->data)));
+
+	for (scan = destination_list; scan != NULL; scan = g_list_next(scan))
+		data->destination_list = g_list_prepend(data->destination_list,
+							g_object_ref (G_FILE (scan->data)));
+
+	data->source_list = g_list_reverse(data->source_list);
+	data->destination_list = g_list_reverse(data->destination_list);
+	data->flags = flags;
+	data->progress_callback = progress_callback;
+	data->progress_data = progress_data;
+	data->progress_data_free = progress_data_free;
+	data->each_file_callback = each_file_callback;
+	data->each_file_data = each_file_data;
+	data->done_func = done_func;
+	data->done_data = done_data;
+	data->done_free = done_free;
+
+	g_io_scheduler_push_job (_async_xfer_job_do, data, 
+				 _async_xfer_data_try_destroy,
+				 io_priority, cancel);
+}
Index: libgthumb/gfile-utils.h
===================================================================
--- libgthumb/gfile-utils.h	(revisão 2394)
+++ libgthumb/gfile-utils.h	(cópia de trabalho)
@@ -34,6 +34,14 @@
 	}					\
 }
 
+typedef struct _AsyncXferEachFile      AsyncXferEachFile;
+typedef struct _AsyncXferData          AsyncXferData;
+typedef void (*AsyncXferEachFileFunc)  (GFile *source, 
+					GFile *destination,
+					GError *error,
+					AsyncXferData *data,
+					gpointer user_data);
+
 /*
  * NOTE: All these functions accept/return _only_ uri-style GFiles.
  */
@@ -91,4 +99,18 @@
 gboolean      gfile_move                       (GFile      *sfile,
 		                                GFile      *dfile);
 
+void          async_xfer_file_gio              (GList *source_list,
+						GList *destination_list,
+						gboolean move_files,
+						GFileCopyFlags flags, 
+						GCancellable *cancel,
+						GFileProgressCallback progress_callback,
+						gpointer progress_data,
+						GDestroyNotify progress_data_free,
+						AsyncXferEachFileFunc each_file_callback,
+						gpointer each_file_data,
+						gint io_priority,
+						GSourceFunc done_func,
+						gpointer done_data,
+						GDestroyNotify done_free);
 #endif /* GFILE_UTILS_H */
Index: src/dlg-file-utils.c
===================================================================
--- src/dlg-file-utils.c	(revisão 2394)
+++ src/dlg-file-utils.c	(cópia de trabalho)
@@ -35,6 +35,7 @@
 #include "comments.h"
 #include "dlg-file-utils.h"
 #include "file-utils.h"
+#include "gfile-utils.h"
 #include "glib-utils.h"
 #include "image-viewer.h"
 #include "main.h"
@@ -1078,7 +1079,8 @@
 	GtkWidget           *progress_cancel;
 
 	guint                timeout_id;
-
+	
+	GError              *error;
 	GnomeVFSAsyncHandle *handle;
 	GnomeVFSResult       result;
 	OverwriteResult      overwrite_result;
@@ -1215,7 +1217,64 @@
 	gtk_widget_show (d);
 }
 
+static void
+continue_or_abort_dialog_gio (FileCopyData   *fcdata,
+			      GError         *error)
+{
+	GtkWidget  *d;
+	const char *src_file;
+	const char *error_desc;
+	char       *message;
+	char       *utf8_name;
+	gboolean    last_file;
 
+	g_clear_error (&fcdata->error);
+	g_propagate_error (&fcdata->error, error);
+	src_file = fcdata->current_file->data;
+
+	if (fcdata->remove_source)
+		error_desc = _("Could not move the image:");
+	else
+		error_desc = _("Could not copy the image:");
+	utf8_name = basename_for_display (src_file);
+	message = g_strconcat (error_desc,
+			       " ",
+			       utf8_name,
+			       "\n\n",
+			       error->message,
+			       NULL);
+	g_free (utf8_name);
+
+	last_file = fcdata->current_file->next == NULL;
+
+	if (last_file)
+		d = _gtk_message_dialog_new (GTK_WINDOW (fcdata->window),
+					     GTK_DIALOG_MODAL,
+					     GTK_STOCK_DIALOG_ERROR,
+					     message,
+					     NULL,
+					     GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
+					     NULL);
+	else
+		d = _gtk_yesno_dialog_new (GTK_WINDOW (fcdata->window),
+					   GTK_DIALOG_MODAL,
+					   message,
+					   _("_Abort"),
+					   _("_Continue"));
+
+	g_free (message);
+
+	g_signal_connect (G_OBJECT (d),
+			  "response",
+			  G_CALLBACK (file_copy__continue_or_abort__response_cb),
+			  fcdata);
+
+	fcdata->continue_dialog_visible = TRUE;
+
+	gtk_widget_hide (fcdata->progress_dialog);
+	gtk_widget_show (d);
+}
+
 static void
 files_copy__done (FileCopyData *fcdata)
 {
@@ -1264,55 +1323,58 @@
 	return TRUE;
 }
 
+static void
+file_progress_update_cb_gio (GFile *source,
+			     GFile *destination,
+			     GError *error,
+			     AsyncXferData *data,
+			     gpointer user_data)
+{
+	FileCopyData *fcdata = user_data;
 
+	if (!error) {
+		if (! fcdata->copying_cache) { /* do not notify cache data. */
+				char *src_file;
+				char *dest_file;
+				
+				src_file = fcdata->current_file->data;
+				dest_file = gfile_get_uri (destination);
+				fcdata->copied_list = g_list_prepend (fcdata->copied_list, src_file);
+				fcdata->created_list = g_list_prepend (fcdata->created_list, dest_file);
+				copy_next_file (fcdata);
+		} else
+			files_copy__done (fcdata);
+	} else
+		continue_or_abort_dialog_gio (fcdata, error);
+}
+
 static void
 xfer_file (FileCopyData *fcdata,
 	   const char   *src_file,
 	   const char   *dest_file)
 {
-	GnomeVFSURI               *src_uri, *dest_uri;
-	GList                     *src_list, *dest_list;
-	GnomeVFSXferOptions        xfer_options;
-	GnomeVFSXferErrorMode      xfer_error_mode;
-	GnomeVFSXferOverwriteMode  overwrite_mode;
-	GnomeVFSResult             result;
+	GList *src_list, *dest_list;
 
-	src_uri = new_uri_from_path (src_file);
-	src_list = g_list_append (NULL, src_uri);
+	src_list = g_list_append (NULL, gfile_new(src_file));
+	dest_list = g_list_append (NULL, gfile_new(dest_file));
 
-	dest_uri = new_uri_from_path (dest_file);
-	dest_list = g_list_append (NULL, dest_uri);
-
-	xfer_options    = fcdata->remove_source ? GNOME_VFS_XFER_REMOVESOURCE : 0;
-	xfer_error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY;
-	overwrite_mode  = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE;
-
 	/* Delete thumbnail from cache, if source file is removed */
 	if (fcdata->remove_source)
 		delete_thumbnail (src_file);
 
-	result = gnome_vfs_async_xfer (&fcdata->handle,
-				       src_list,
-				       dest_list,
-				       xfer_options,
-				       xfer_error_mode,
-				       overwrite_mode,
-				       GNOME_VFS_PRIORITY_DEFAULT,
-				       file_progress_update_cb,
-				       fcdata,
-				       NULL,
-				       NULL);
+	async_xfer_file_gio (src_list,
+			     dest_list,
+			     fcdata->remove_source,
+			     G_FILE_COPY_OVERWRITE, 
+			     NULL, NULL, NULL, NULL,
+			     file_progress_update_cb_gio,
+			     fcdata, G_PRIORITY_DEFAULT,
+			     NULL, NULL, NULL);
 
-	gnome_vfs_uri_unref (src_uri);
+	g_list_foreach (src_list, (GFunc) g_object_unref, NULL);
 	g_list_free (src_list);
-
-	gnome_vfs_uri_unref (dest_uri);
+	g_list_foreach (dest_list, (GFunc) g_object_unref, NULL);
 	g_list_free (dest_list);
-
-	/**/
-
-	if (result != GNOME_VFS_OK)
-		continue_or_abort_dialog (fcdata, result);
 }
 
 
@@ -1615,7 +1677,7 @@
 		fcdata->overwrite_result = OVERWRITE_RESULT_NO;
 	fcdata->cache_copied = FALSE;
 	fcdata->copying_cache = FALSE;
-
+	fcdata->error = NULL;
 	fcdata->file_index = 1;
 	fcdata->files_total = g_list_length (file_list);
 	fcdata->continue_dialog_visible = FALSE;
