diff --git a/gio/ChangeLog b/gio/ChangeLog index c6d3f9ed9..15d6d2b64 100644 --- a/gio/ChangeLog +++ b/gio/ChangeLog @@ -1,3 +1,11 @@ +2008-01-24 Alexander Larsson + + * gfile.[ch]: + * gfile.h: + * gio.symbols: + Add g_file_copy_async() (#511580) + Based on patch from Carlos Garcia Campos + 2008-01-23 Matthias Clasen * gioscheduler.c: Some documentation additions. diff --git a/gio/gfile.c b/gio/gfile.c index b9d126d89..e1d9a9546 100644 --- a/gio/gfile.c +++ b/gio/gfile.c @@ -90,97 +90,108 @@ static void g_file_base_init (gpointer g_class); static void g_file_class_init (gpointer g_class, gpointer class_data); -static void g_file_real_query_info_async (GFile *file, - const char *attributes, - GFileQueryInfoFlags flags, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static GFileInfo * g_file_real_query_info_finish (GFile *file, - GAsyncResult *res, - GError **error); -static void g_file_real_enumerate_children_async (GFile *file, - const char *attributes, - GFileQueryInfoFlags flags, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static GFileEnumerator * g_file_real_enumerate_children_finish (GFile *file, - GAsyncResult *res, - GError **error); -static void g_file_real_read_async (GFile *file, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static GFileInputStream * g_file_real_read_finish (GFile *file, - GAsyncResult *res, - GError **error); -static void g_file_real_append_to_async (GFile *file, - GFileCreateFlags flags, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static GFileOutputStream *g_file_real_append_to_finish (GFile *file, - GAsyncResult *res, - GError **error); -static void g_file_real_create_async (GFile *file, - GFileCreateFlags flags, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static GFileOutputStream *g_file_real_create_finish (GFile *file, - GAsyncResult *res, - GError **error); -static void g_file_real_replace_async (GFile *file, - const char *etag, - gboolean make_backup, - GFileCreateFlags flags, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static GFileOutputStream *g_file_real_replace_finish (GFile *file, - GAsyncResult *res, - GError **error); -static gboolean g_file_real_set_attributes_from_info (GFile *file, - GFileInfo *info, - GFileQueryInfoFlags flags, - GCancellable *cancellable, - GError **error); -static void g_file_real_set_display_name_async (GFile *file, - const char *display_name, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static GFile * g_file_real_set_display_name_finish (GFile *file, - GAsyncResult *res, - GError **error); -static void g_file_real_set_attributes_async (GFile *file, - GFileInfo *info, - GFileQueryInfoFlags flags, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static gboolean g_file_real_set_attributes_finish (GFile *file, - GAsyncResult *res, - GFileInfo **info, - GError **error); -static void g_file_real_find_enclosing_mount_async (GFile *file, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -static GMount * g_file_real_find_enclosing_mount_finish (GFile *file, - GAsyncResult *res, - GError **error); - +static void g_file_real_query_info_async (GFile *file, + const char *attributes, + GFileQueryInfoFlags flags, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static GFileInfo * g_file_real_query_info_finish (GFile *file, + GAsyncResult *res, + GError **error); +static void g_file_real_enumerate_children_async (GFile *file, + const char *attributes, + GFileQueryInfoFlags flags, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static GFileEnumerator * g_file_real_enumerate_children_finish (GFile *file, + GAsyncResult *res, + GError **error); +static void g_file_real_read_async (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static GFileInputStream * g_file_real_read_finish (GFile *file, + GAsyncResult *res, + GError **error); +static void g_file_real_append_to_async (GFile *file, + GFileCreateFlags flags, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static GFileOutputStream *g_file_real_append_to_finish (GFile *file, + GAsyncResult *res, + GError **error); +static void g_file_real_create_async (GFile *file, + GFileCreateFlags flags, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static GFileOutputStream *g_file_real_create_finish (GFile *file, + GAsyncResult *res, + GError **error); +static void g_file_real_replace_async (GFile *file, + const char *etag, + gboolean make_backup, + GFileCreateFlags flags, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static GFileOutputStream *g_file_real_replace_finish (GFile *file, + GAsyncResult *res, + GError **error); +static gboolean g_file_real_set_attributes_from_info (GFile *file, + GFileInfo *info, + GFileQueryInfoFlags flags, + GCancellable *cancellable, + GError **error); +static void g_file_real_set_display_name_async (GFile *file, + const char *display_name, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static GFile * g_file_real_set_display_name_finish (GFile *file, + GAsyncResult *res, + GError **error); +static void g_file_real_set_attributes_async (GFile *file, + GFileInfo *info, + GFileQueryInfoFlags flags, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static gboolean g_file_real_set_attributes_finish (GFile *file, + GAsyncResult *res, + GFileInfo **info, + GError **error); +static void g_file_real_find_enclosing_mount_async (GFile *file, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +static GMount * g_file_real_find_enclosing_mount_finish (GFile *file, + GAsyncResult *res, + GError **error); +static void g_file_real_copy_async (GFile *source, + GFile *destination, + GFileCopyFlags flags, + int io_priority, + GCancellable *cancellable, + GFileProgressCallback progress_callback, + gpointer progress_callback_data, + GAsyncReadyCallback callback, + gpointer user_data); +static gboolean g_file_real_copy_finish (GFile *file, + GAsyncResult *res, + GError **error); GType g_file_get_type (void) @@ -237,6 +248,8 @@ g_file_class_init (gpointer g_class, iface->find_enclosing_mount_async = g_file_real_find_enclosing_mount_async; iface->find_enclosing_mount_finish = g_file_real_find_enclosing_mount_finish; iface->set_attributes_from_info = g_file_real_set_attributes_from_info; + iface->copy_async = g_file_real_copy_async; + iface->copy_finish = g_file_real_copy_finish; } static void @@ -2243,6 +2256,87 @@ g_file_copy (GFile *source, error); } +/** + * g_file_copy_async: + * @source: input #GFile. + * @destination: destination #GFile + * @flags: set of #GFileCopyFlags + * @cancellable: optional #GCancellable object, %NULL to ignore. + * @progress_callback: function to callback with progress information + * @progress_callback_data: user data to pass to @progress_callback + * @callback: a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: the data to pass to callback function + * + * Copies the file @source to the location specified by @destination asynchronously. + * For details of the behaviour, see g_file_copy(). + * + * If @progress_callback is not %NULL, then that function that will be called + * just like in g_file_copy(), however the callback will run in the main loop, + * not in the thread that is doing the I/O operation. + * + * When the operation is finished, @callback will be called. You can then call + * g_file_copy_finish() to get the result of the operation. + **/ +void +g_file_copy_async (GFile *source, + GFile *destination, + GFileCopyFlags flags, + int io_priority, + GCancellable *cancellable, + GFileProgressCallback progress_callback, + gpointer progress_callback_data, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GFileIface *iface; + + g_return_if_fail (G_IS_FILE (source)); + g_return_if_fail (G_IS_FILE (destination)); + + iface = G_FILE_GET_IFACE (source); + (* iface->copy_async) (source, + destination, + flags, + io_priority, + cancellable, + progress_callback, + progress_callback_data, + callback, + user_data); +} + +/** + * g_file_copy_finish: + * @file: input #GFile. + * @res: a #GAsyncResult. + * @error: a #GError, or %NULL + * + * Finishes copying the file started with + * g_file_copy_async(). + * + * Returns: a %TRUE on success, %FALSE on error. + **/ +gboolean +g_file_copy_finish (GFile *file, + GAsyncResult *res, + GError **error) +{ + GFileIface *iface; + + g_return_val_if_fail (G_IS_FILE (file), FALSE); + g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE); + + if (G_IS_SIMPLE_ASYNC_RESULT (res)) + { + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + } + + iface = G_FILE_GET_IFACE (file); + return (* iface->copy_finish) (file, res, error); +} /** * g_file_move: @@ -4133,6 +4227,145 @@ g_file_real_find_enclosing_mount_finish (GFile *file, } +typedef struct { + GFile *source; + GFile *destination; + GFileCopyFlags flags; + GFileProgressCallback progress_cb; + gpointer progress_cb_data; + GIOSchedulerJob *job; +} CopyAsyncData; + +static void +copy_async_data_free (CopyAsyncData *data) +{ + g_object_unref (data->source); + g_object_unref (data->destination); + g_free (data); +} + +typedef struct { + CopyAsyncData *data; + goffset current_num_bytes; + goffset total_num_bytes; +} ProgressData; + +static gboolean +copy_async_progress_in_main (gpointer user_data) +{ + ProgressData *progress = user_data; + CopyAsyncData *data = progress->data; + + data->progress_cb (progress->current_num_bytes, + progress->total_num_bytes, + data->progress_cb_data); + + return FALSE; +} + +static gboolean +mainloop_barrier (gpointer user_data) +{ + /* Does nothing, but ensures all queued idles before + this are run */ + return FALSE; +} + + +static void +copy_async_progress_callback (goffset current_num_bytes, + goffset total_num_bytes, + gpointer user_data) +{ + CopyAsyncData *data = user_data; + ProgressData *progress; + + progress = g_new (ProgressData, 1); + progress->data = data; + progress->current_num_bytes = current_num_bytes; + progress->total_num_bytes = total_num_bytes; + + g_io_scheduler_job_send_to_mainloop_async (data->job, + copy_async_progress_in_main, + progress, + g_free); +} + +static void +copy_async_thread (GIOSchedulerJob *job, + GCancellable *cancellable, + gpointer user_data) +{ + GSimpleAsyncResult *res; + CopyAsyncData *data; + gboolean result; + GError *error; + + res = user_data; + data = g_simple_async_result_get_op_res_gpointer (res); + + error = NULL; + data->job = job; + result = g_file_copy (data->source, + data->destination, + data->flags, + cancellable, + (data->progress_cb != NULL) ? copy_async_progress_callback : NULL, + data, + &error); + + /* Ensure all progress callbacks are done running in main thread */ + if (data->progress_cb != NULL) + g_io_scheduler_job_send_to_mainloop (job, + mainloop_barrier, + NULL, NULL); + + if (!result) + { + g_simple_async_result_set_from_error (res, error); + g_error_free (error); + } + + g_simple_async_result_complete_in_idle (res); +} + +static void +g_file_real_copy_async (GFile *source, + GFile *destination, + GFileCopyFlags flags, + int io_priority, + GCancellable *cancellable, + GFileProgressCallback progress_callback, + gpointer progress_callback_data, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + CopyAsyncData *data; + + data = g_new0 (CopyAsyncData, 1); + data->source = g_object_ref (source); + data->destination = g_object_ref (destination); + data->flags = flags; + data->progress_cb = progress_callback; + data->progress_cb_data = progress_callback_data; + + res = g_simple_async_result_new (G_OBJECT (source), callback, user_data, g_file_real_copy_async); + g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)copy_async_data_free); + + g_io_scheduler_push_job (copy_async_thread, res, g_object_unref, io_priority, cancellable); +} + +static gboolean +g_file_real_copy_finish (GFile *file, + GAsyncResult *res, + GError **error) +{ + /* Error handled in g_file_copy_finish() */ + return TRUE; +} + + /******************************************** * Default VFS operations * ********************************************/ diff --git a/gio/gfile.h b/gio/gfile.h index 797daa457..196d040e7 100644 --- a/gio/gfile.h +++ b/gio/gfile.h @@ -228,8 +228,8 @@ typedef gboolean (* GFileReadMoreCallback) (const char *file_contents, * @_make_symbolic_link_async: Asynchronously makes a symbolic link * @_make_symbolic_link_finish: Finishes making a symbolic link asynchronously. * @copy: Copies a file. - * @_copy_async: Asynchronously copies a file. - * @_copy_finish: Finishes an asynchronous copy operation. + * @copy_async: Asynchronously copies a file. + * @copy_finish: Finishes an asynchronous copy operation. * @move: Moves a file. * @_move_async: Asynchronously moves a file. * @_move_finish: Finishes an asynchronous move operation. @@ -466,8 +466,18 @@ struct _GFileIface GFileProgressCallback progress_callback, gpointer progress_callback_data, GError **error); - void (*_copy_async) (void); - void (*_copy_finish) (void); + void (*copy_async) (GFile *source, + GFile *destination, + GFileCopyFlags flags, + int io_priority, + GCancellable *cancellable, + GFileProgressCallback progress_callback, + gpointer progress_callback_data, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*copy_finish) (GFile *file, + GAsyncResult *res, + GError **error); gboolean (*move) (GFile *source, GFile *destination, @@ -685,6 +695,18 @@ gboolean g_file_copy (GFile GFileProgressCallback progress_callback, gpointer progress_callback_data, GError **error); +void g_file_copy_async (GFile *source, + GFile *destination, + GFileCopyFlags flags, + int io_priority, + GCancellable *cancellable, + GFileProgressCallback progress_callback, + gpointer progress_callback_data, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean g_file_copy_finish (GFile *file, + GAsyncResult *res, + GError **error); gboolean g_file_move (GFile *source, GFile *destination, GFileCopyFlags flags, diff --git a/gio/gio.symbols b/gio/gio.symbols index e39552339..bbb7b1087 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -260,6 +260,8 @@ g_file_set_display_name_finish g_file_delete g_file_trash g_file_copy +g_file_copy_async +g_file_copy_finish g_file_move g_file_make_directory g_file_make_symbolic_link