Implement async file movement

This commit is contained in:
Lucas Schwiderski 2022-02-03 12:20:36 +01:00 committed by Philip Withnall
parent 1cdb0f8bed
commit eeb2bcf5a9
3 changed files with 248 additions and 4 deletions

View File

@ -149,6 +149,8 @@ g_file_copy
g_file_copy_async
g_file_copy_finish
g_file_move
g_file_move_async
g_file_move_finish
g_file_make_directory
g_file_make_directory_async
g_file_make_directory_finish

View File

@ -247,6 +247,18 @@ static void g_file_real_trash_async (GFile
static gboolean g_file_real_trash_finish (GFile *file,
GAsyncResult *res,
GError **error);
static void g_file_real_move_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_move_finish (GFile *file,
GAsyncResult *result,
GError **error);
static void g_file_real_make_directory_async (GFile *file,
int io_priority,
GCancellable *cancellable,
@ -381,6 +393,8 @@ g_file_default_init (GFileIface *iface)
iface->delete_file_finish = g_file_real_delete_finish;
iface->trash_async = g_file_real_trash_async;
iface->trash_finish = g_file_real_trash_finish;
iface->move_async = g_file_real_move_async;
iface->move_finish = g_file_real_move_finish;
iface->make_directory_async = g_file_real_make_directory_async;
iface->make_directory_finish = g_file_real_make_directory_finish;
iface->open_readwrite_async = g_file_real_open_readwrite_async;
@ -3770,6 +3784,91 @@ g_file_move (GFile *source,
return g_file_delete (source, cancellable, error);
}
/**
* g_file_move_async:
* @source: #GFile pointing to the source location
* @destination: #GFile pointing to the destination location
* @flags: set of #GFileCopyFlags
* @io_priority: the [I/O priority][io-priority] of the request
* @cancellable: (nullable): optional #GCancellable object,
* %NULL to ignore
* @progress_callback: (nullable) (scope call): #GFileProgressCallback
* function for updates
* @progress_callback_data: (closure): gpointer to user data for
* the callback function
* @callback: a #GAsyncReadyCallback to call
* when the request is satisfied
* @user_data: the data to pass to callback function
*
* Asynchronously moves a file @source to the location of @destination. For details of the behaviour, see g_file_move().
*
* If @progress_callback is not %NULL, then that function that will be called
* just like in g_file_move(). The callback will run in the default main context
* of the thread calling g_file_move_async() the same context as @callback is
* run in.
*
* When the operation is finished, @callback will be called. You can then call
* g_file_move_finish() to get the result of the operation.
*
* Since: 2.72
*/
void
g_file_move_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));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
iface = G_FILE_GET_IFACE (source);
(* iface->move_async) (source,
destination,
flags,
io_priority,
cancellable,
progress_callback,
progress_callback_data,
callback,
user_data);
}
/**
* g_file_move_finish:
* @file: input source #GFile
* @result: a #GAsyncResult
* @error: a #GError, or %NULL
*
* Finishes an asynchronous file movement, started with
* g_file_move_async().
*
* Returns: %TRUE on successful file move, %FALSE otherwise.
*
* Since: 2.72
*/
gboolean
g_file_move_finish (GFile *file,
GAsyncResult *result,
GError **error)
{
GFileIface *iface;
g_return_val_if_fail (G_IS_FILE (file), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
iface = G_FILE_GET_IFACE (file);
return (* iface->move_finish) (file, result, error);
}
/**
* g_file_make_directory:
* @file: input #GFile
@ -6004,6 +6103,125 @@ g_file_real_trash_finish (GFile *file,
return g_task_propagate_boolean (G_TASK (res), error);
}
typedef struct {
GFile *source; /* (owned) */
GFile *destination; /* (owned) */
GFileCopyFlags flags;
GFileProgressCallback progress_cb;
gpointer progress_cb_data;
} MoveAsyncData;
static void
move_async_data_free (MoveAsyncData *data)
{
g_object_unref (data->source);
g_object_unref (data->destination);
g_slice_free (MoveAsyncData, data);
}
typedef struct {
MoveAsyncData *data; /* (unowned) */
goffset current_num_bytes;
goffset total_num_bytes;
} MoveProgressData;
static gboolean
move_async_progress_in_main (gpointer user_data)
{
MoveProgressData *progress = user_data;
MoveAsyncData *data = progress->data;
data->progress_cb (progress->current_num_bytes,
progress->total_num_bytes,
data->progress_cb_data);
return G_SOURCE_REMOVE;
}
static void
move_async_progress_callback (goffset current_num_bytes,
goffset total_num_bytes,
gpointer user_data)
{
GTask *task = user_data;
MoveAsyncData *data = g_task_get_task_data (task);
MoveProgressData *progress;
progress = g_new0 (MoveProgressData, 1);
progress->data = data;
progress->current_num_bytes = current_num_bytes;
progress->total_num_bytes = total_num_bytes;
g_main_context_invoke_full (g_task_get_context (task),
g_task_get_priority (task),
move_async_progress_in_main,
g_steal_pointer (&progress),
g_free);
}
static void
move_async_thread (GTask *task,
gpointer source,
gpointer task_data,
GCancellable *cancellable)
{
MoveAsyncData *data = task_data;
gboolean result;
GError *error = NULL;
result = g_file_move (data->source,
data->destination,
data->flags,
cancellable,
(data->progress_cb != NULL) ? move_async_progress_callback : NULL,
task,
&error);
if (result)
g_task_return_boolean (task, TRUE);
else
g_task_return_error (task, g_steal_pointer (&error));
}
static void
g_file_real_move_async (GFile *source,
GFile *destination,
GFileCopyFlags flags,
int io_priority,
GCancellable *cancellable,
GFileProgressCallback progress_callback,
gpointer progress_callback_data,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
MoveAsyncData *data;
data = g_slice_new0 (MoveAsyncData);
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;
task = g_task_new (source, cancellable, callback, user_data);
g_task_set_source_tag (task, g_file_real_move_async);
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) move_async_data_free);
g_task_set_priority (task, io_priority);
g_task_run_in_thread (task, move_async_thread);
g_object_unref (task);
}
static gboolean
g_file_real_move_finish (GFile *file,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, file), FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
make_directory_async_thread (GTask *task,
gpointer object,

View File

@ -121,8 +121,8 @@ typedef struct _GFileIface GFileIface;
* @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.
* @move_async: Asynchronously moves a file. Since: 2.72
* @move_finish: Finishes an asynchronous move operation. Since: 2.72
* @mount_mountable: Mounts a mountable object.
* @mount_mountable_finish: Finishes a mounting operation.
* @unmount_mountable: Unmounts a mountable object.
@ -424,8 +424,18 @@ struct _GFileIface
GFileProgressCallback progress_callback,
gpointer progress_callback_data,
GError **error);
void (* _move_async) (void);
void (* _move_finish) (void);
void (* move_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 (* move_finish) (GFile *file,
GAsyncResult *result,
GError **error);
void (* mount_mountable) (GFile *file,
GMountMountFlags flags,
@ -926,6 +936,20 @@ gboolean g_file_move (GFile
GFileProgressCallback progress_callback,
gpointer progress_callback_data,
GError **error);
GLIB_AVAILABLE_IN_2_72
void g_file_move_async (GFile *source,
GFile *destination,
GFileCopyFlags flags,
int io_priority,
GCancellable *cancellable,
GFileProgressCallback progress_callback,
gpointer progress_callback_data,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_2_72
gboolean g_file_move_finish (GFile *file,
GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_file_make_directory (GFile *file,
GCancellable *cancellable,