[glib: 1/4] Implement async file movement




commit eeb2bcf5a923b0521a69f525ff9c5243e2d3b45f
Author: Lucas Schwiderski <lucas lschwiderski de>
Date:   Thu Feb 3 12:20:36 2022 +0100

    Implement async file movement

 docs/reference/gio/gio-sections-common.txt |   2 +
 gio/gfile.c                                | 218 +++++++++++++++++++++++++++++
 gio/gfile.h                                |  32 ++++-
 3 files changed, 248 insertions(+), 4 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt
index 9f5d3d332..4842deaf7 100644
--- a/docs/reference/gio/gio-sections-common.txt
+++ b/docs/reference/gio/gio-sections-common.txt
@@ -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
diff --git a/gio/gfile.c b/gio/gfile.c
index 6208c2f81..30daad3b6 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -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,
diff --git a/gio/gfile.h b/gio/gfile.h
index 4cff1a372..3a324cf9d 100644
--- a/gio/gfile.h
+++ b/gio/gfile.h
@@ -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,


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