mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 15:36:17 +01:00
Merge branch 'copy-move-async-with-closures' into 'main'
Add g_file_copy_async_with_closures() and g_file_move_async_with_closures() See merge request GNOME/glib!3939
This commit is contained in:
commit
71d60faef3
153
gio/gfile.c
153
gio/gfile.c
@ -3818,6 +3818,123 @@ g_file_copy_async (GFile *source,
|
||||
user_data);
|
||||
}
|
||||
|
||||
typedef struct _CopyAsyncClosuresData
|
||||
{
|
||||
GClosure *progress_callback_closure;
|
||||
GClosure *ready_callback_closure;
|
||||
} CopyAsyncClosuresData;
|
||||
|
||||
static CopyAsyncClosuresData *
|
||||
copy_async_closures_data_new (GClosure *progress_callback_closure,
|
||||
GClosure *ready_callback_closure)
|
||||
{
|
||||
CopyAsyncClosuresData *data;
|
||||
|
||||
data = g_new0 (CopyAsyncClosuresData, 1);
|
||||
|
||||
if (progress_callback_closure != NULL)
|
||||
{
|
||||
data->progress_callback_closure = g_closure_ref (progress_callback_closure);
|
||||
g_closure_sink (progress_callback_closure);
|
||||
if (G_CLOSURE_NEEDS_MARSHAL (progress_callback_closure))
|
||||
g_closure_set_marshal (progress_callback_closure, g_cclosure_marshal_generic);
|
||||
}
|
||||
|
||||
data->ready_callback_closure = g_closure_ref (ready_callback_closure);
|
||||
g_closure_sink (ready_callback_closure);
|
||||
if (G_CLOSURE_NEEDS_MARSHAL (ready_callback_closure))
|
||||
g_closure_set_marshal (ready_callback_closure, g_cclosure_marshal_generic);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_async_closures_data_free (CopyAsyncClosuresData *data)
|
||||
{
|
||||
if (data->progress_callback_closure != NULL)
|
||||
g_closure_unref (data->progress_callback_closure);
|
||||
|
||||
g_closure_unref (data->ready_callback_closure);
|
||||
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_async_invoke_progress (goffset current_num_bytes,
|
||||
goffset total_num_bytes,
|
||||
void *user_data)
|
||||
{
|
||||
CopyAsyncClosuresData *data = (CopyAsyncClosuresData *) user_data;
|
||||
GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
|
||||
|
||||
/* goffset is 64-bits even on 32-bits platforms */
|
||||
g_value_init (¶ms[0], G_TYPE_INT64);
|
||||
g_value_set_int64 (¶ms[0], current_num_bytes);
|
||||
g_value_init (¶ms[1], G_TYPE_INT64);
|
||||
g_value_set_int64 (¶ms[1], total_num_bytes);
|
||||
|
||||
g_closure_invoke (data->progress_callback_closure, /* result = */ NULL, 2, params, /* hint = */ NULL);
|
||||
|
||||
g_value_unset (¶ms[0]);
|
||||
g_value_unset (¶ms[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_async_invoke_ready (GObject *file,
|
||||
GAsyncResult *result,
|
||||
void *user_data)
|
||||
{
|
||||
CopyAsyncClosuresData *data = (CopyAsyncClosuresData *) user_data;
|
||||
GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
|
||||
|
||||
g_value_init (¶ms[0], G_TYPE_FILE);
|
||||
g_value_set_object (¶ms[0], file);
|
||||
g_value_init (¶ms[1], G_TYPE_ASYNC_RESULT);
|
||||
g_value_set_object (¶ms[1], result);
|
||||
|
||||
g_closure_invoke (data->ready_callback_closure, /* result = */ NULL, 2, params, /* hint = */ NULL);
|
||||
|
||||
copy_async_closures_data_free (data);
|
||||
g_value_unset (¶ms[0]);
|
||||
g_value_unset (¶ms[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_file_copy_async_with_closures: (rename-to g_file_copy_async) (finish-func g_file_copy_finish):
|
||||
* @source: input [type@Gio.File]
|
||||
* @destination: destination [type@Gio.File]
|
||||
* @flags: set of [flags@Gio.FileCopyFlags]
|
||||
* @io_priority: the [I/O priority](iface.AsyncResult.html#io-priority) of the request
|
||||
* @cancellable: (nullable): optional [class@Gio.Cancellable] object,
|
||||
* `NULL` to ignore
|
||||
* @progress_callback_closure: (nullable): [type@GObject.Closure] to invoke with progress
|
||||
* information, or `NULL` if progress information is not needed
|
||||
* @ready_callback_closure: (not nullable): [type@GObject.Closure] to invoke when the request is satisfied
|
||||
*
|
||||
* Version of [method@Gio.File.copy_async] using closures instead of callbacks for
|
||||
* easier binding in other languages.
|
||||
*
|
||||
* Since: 2.82
|
||||
*/
|
||||
void
|
||||
g_file_copy_async_with_closures (GFile *source,
|
||||
GFile *destination,
|
||||
GFileCopyFlags flags,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GClosure *progress_callback_closure,
|
||||
GClosure *ready_callback_closure)
|
||||
{
|
||||
CopyAsyncClosuresData *data;
|
||||
|
||||
/* freed in copy_async_invoke_ready */
|
||||
data = copy_async_closures_data_new (progress_callback_closure, ready_callback_closure);
|
||||
|
||||
g_file_copy_async (source, destination, flags, io_priority, cancellable,
|
||||
progress_callback_closure == NULL ? NULL : copy_async_invoke_progress, data,
|
||||
copy_async_invoke_ready, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_file_copy_finish:
|
||||
* @file: input #GFile
|
||||
@ -4035,6 +4152,42 @@ g_file_move_async (GFile *source,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_file_move_async_with_closures: (rename-to g_file_move_async) (finish-func g_file_move_finish):
|
||||
* @source: input [type@Gio.File]
|
||||
* @destination: destination [type@Gio.File]
|
||||
* @flags: set of [flags@Gio.FileCopyFlags]
|
||||
* @io_priority: the [I/O priority](iface.AsyncResult.html#io-priority) of the request
|
||||
* @cancellable: (nullable): optional [class@Gio.Cancellable] object,
|
||||
* `NULL` to ignore
|
||||
* @progress_callback_closure: (nullable): [type@GObject.Closure] to invoke with progress
|
||||
* information, or `NULL` if progress information is not needed
|
||||
* @ready_callback_closure: (not nullable): [type@GObject.Closure] to invoke when the request is satisfied
|
||||
*
|
||||
* Version of [method@Gio.File.move_async] using closures instead of callbacks for
|
||||
* easier binding in other languages.
|
||||
*
|
||||
* Since: 2.82
|
||||
*/
|
||||
void
|
||||
g_file_move_async_with_closures (GFile *source,
|
||||
GFile *destination,
|
||||
GFileCopyFlags flags,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GClosure *progress_callback_closure,
|
||||
GClosure *ready_callback_closure)
|
||||
{
|
||||
CopyAsyncClosuresData *data;
|
||||
|
||||
/* freed in copy_async_invoke_ready */
|
||||
data = copy_async_closures_data_new (progress_callback_closure, ready_callback_closure);
|
||||
|
||||
g_file_move_async (source, destination, flags, io_priority, cancellable,
|
||||
progress_callback_closure == NULL ? NULL : copy_async_invoke_progress, data,
|
||||
copy_async_invoke_ready, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_file_move_finish:
|
||||
* @file: input source #GFile
|
||||
|
16
gio/gfile.h
16
gio/gfile.h
@ -944,6 +944,14 @@ void g_file_copy_async (GFile
|
||||
gpointer progress_callback_data,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GIO_AVAILABLE_IN_2_82
|
||||
void g_file_copy_async_with_closures (GFile *source,
|
||||
GFile *destination,
|
||||
GFileCopyFlags flags,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GClosure *progress_callback_closure,
|
||||
GClosure *ready_callback_closure);
|
||||
GIO_AVAILABLE_IN_ALL
|
||||
gboolean g_file_copy_finish (GFile *file,
|
||||
GAsyncResult *res,
|
||||
@ -966,6 +974,14 @@ void g_file_move_async (GFile
|
||||
gpointer progress_callback_data,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GIO_AVAILABLE_IN_2_82
|
||||
void g_file_move_async_with_closures (GFile *source,
|
||||
GFile *destination,
|
||||
GFileCopyFlags flags,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GClosure *progress_callback_closure,
|
||||
GClosure *ready_callback_closure);
|
||||
GIO_AVAILABLE_IN_2_72
|
||||
gboolean g_file_move_finish (GFile *file,
|
||||
GAsyncResult *result,
|
||||
|
189
gio/tests/file.c
189
gio/tests/file.c
@ -2606,6 +2606,119 @@ test_copy_progress (void)
|
||||
g_clear_object (&dest_tmpfile);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GError *error;
|
||||
gboolean done;
|
||||
gboolean res;
|
||||
} CopyAsyncData;
|
||||
|
||||
static void
|
||||
test_copy_async_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
void *user_data)
|
||||
{
|
||||
GFile *file = G_FILE (object);
|
||||
CopyAsyncData *data = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
data->res = g_file_move_finish (file, result, &error);
|
||||
data->error = g_steal_pointer (&error);
|
||||
data->done = TRUE;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
goffset total_num_bytes;
|
||||
} CopyAsyncProgressData;
|
||||
|
||||
static void
|
||||
test_copy_async_progress_cb (goffset current_num_bytes,
|
||||
goffset total_num_bytes,
|
||||
void *user_data)
|
||||
{
|
||||
CopyAsyncProgressData *data = user_data;
|
||||
data->total_num_bytes = total_num_bytes;
|
||||
}
|
||||
|
||||
/* Exercise copy_async_with_closures() */
|
||||
static void
|
||||
test_copy_async_with_closures (void)
|
||||
{
|
||||
CopyAsyncData data = { 0 };
|
||||
CopyAsyncProgressData progress_data = { 0 };
|
||||
GFile *source;
|
||||
GFileIOStream *iostream;
|
||||
GOutputStream *ostream;
|
||||
GFile *destination;
|
||||
gchar *destination_path;
|
||||
GError *error = NULL;
|
||||
gboolean res;
|
||||
const guint8 buffer[] = { 1, 2, 3, 4, 5 };
|
||||
GClosure *progress_closure;
|
||||
GClosure *ready_closure;
|
||||
|
||||
source = g_file_new_tmp ("g_file_copy_async_with_closures_XXXXXX", &iostream, NULL);
|
||||
|
||||
destination_path = g_build_path (G_DIR_SEPARATOR_S, g_get_tmp_dir (), "g_file_copy_async_with_closures_target", NULL);
|
||||
destination = g_file_new_for_path (destination_path);
|
||||
|
||||
g_assert_nonnull (source);
|
||||
g_assert_nonnull (iostream);
|
||||
|
||||
res = g_file_query_exists (source, NULL);
|
||||
g_assert_true (res);
|
||||
res = g_file_query_exists (destination, NULL);
|
||||
g_assert_false (res);
|
||||
|
||||
/* Write a known number of bytes to the file, so we can test the progress
|
||||
* callback against it */
|
||||
ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
|
||||
g_output_stream_write (ostream, buffer, sizeof (buffer), NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
progress_closure = g_cclosure_new (G_CALLBACK (test_copy_async_progress_cb), &progress_data, NULL);
|
||||
ready_closure = g_cclosure_new (G_CALLBACK (test_copy_async_cb), &data, NULL);
|
||||
|
||||
g_file_copy_async_with_closures (source,
|
||||
destination,
|
||||
G_FILE_COPY_NONE,
|
||||
0,
|
||||
NULL,
|
||||
progress_closure,
|
||||
ready_closure);
|
||||
|
||||
while (!data.done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
g_assert_no_error (data.error);
|
||||
g_assert_true (data.res);
|
||||
g_assert_cmpuint (progress_data.total_num_bytes, ==, sizeof (buffer));
|
||||
|
||||
res = g_file_query_exists (source, NULL);
|
||||
g_assert_true (res);
|
||||
res = g_file_query_exists (destination, NULL);
|
||||
g_assert_true (res);
|
||||
|
||||
res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_true (res);
|
||||
g_object_unref (iostream);
|
||||
|
||||
res = g_file_delete (source, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_true (res);
|
||||
|
||||
res = g_file_delete (destination, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_true (res);
|
||||
|
||||
g_object_unref (source);
|
||||
g_object_unref (destination);
|
||||
|
||||
g_free (destination_path);
|
||||
}
|
||||
|
||||
static void
|
||||
test_measure (void)
|
||||
{
|
||||
@ -3577,6 +3690,80 @@ test_move_async (void)
|
||||
g_free (destination_path);
|
||||
}
|
||||
|
||||
/* Same test as for move_async(), but for move_async_with_closures() */
|
||||
static void
|
||||
test_move_async_with_closures (void)
|
||||
{
|
||||
MoveAsyncData data = { 0 };
|
||||
MoveAsyncProgressData progress_data = { 0 };
|
||||
GFile *source;
|
||||
GFileIOStream *iostream;
|
||||
GOutputStream *ostream;
|
||||
GFile *destination;
|
||||
gchar *destination_path;
|
||||
GError *error = NULL;
|
||||
gboolean res;
|
||||
const guint8 buffer[] = { 1, 2, 3, 4, 5 };
|
||||
GClosure *progress_closure;
|
||||
GClosure *ready_closure;
|
||||
|
||||
source = g_file_new_tmp ("g_file_move_async_with_closures_XXXXXX", &iostream, NULL);
|
||||
|
||||
destination_path = g_build_path (G_DIR_SEPARATOR_S, g_get_tmp_dir (), "g_file_move_async_with_closures_target", NULL);
|
||||
destination = g_file_new_for_path (destination_path);
|
||||
|
||||
g_assert_nonnull (source);
|
||||
g_assert_nonnull (iostream);
|
||||
|
||||
res = g_file_query_exists (source, NULL);
|
||||
g_assert_true (res);
|
||||
res = g_file_query_exists (destination, NULL);
|
||||
g_assert_false (res);
|
||||
|
||||
/* Write a known number of bytes to the file, so we can test the progress
|
||||
* callback against it */
|
||||
ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
|
||||
g_output_stream_write (ostream, buffer, sizeof (buffer), NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
progress_closure = g_cclosure_new (G_CALLBACK (test_move_async_progress_cb), &progress_data, NULL);
|
||||
ready_closure = g_cclosure_new (G_CALLBACK (test_move_async_cb), &data, NULL);
|
||||
|
||||
g_file_move_async_with_closures (source,
|
||||
destination,
|
||||
G_FILE_COPY_NONE,
|
||||
0,
|
||||
NULL,
|
||||
progress_closure,
|
||||
ready_closure);
|
||||
|
||||
while (!data.done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
g_assert_no_error (data.error);
|
||||
g_assert_true (data.res);
|
||||
g_assert_cmpuint (progress_data.total_num_bytes, ==, sizeof (buffer));
|
||||
|
||||
res = g_file_query_exists (source, NULL);
|
||||
g_assert_false (res);
|
||||
res = g_file_query_exists (destination, NULL);
|
||||
g_assert_true (res);
|
||||
|
||||
res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_true (res);
|
||||
g_object_unref (iostream);
|
||||
|
||||
res = g_file_delete (destination, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_true (res);
|
||||
|
||||
g_object_unref (source);
|
||||
g_object_unref (destination);
|
||||
|
||||
g_free (destination_path);
|
||||
}
|
||||
|
||||
static GAppInfo *
|
||||
create_command_line_app_info (const char *name,
|
||||
const char *command_line,
|
||||
@ -4028,6 +4215,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/file/async-make-symlink", test_async_make_symlink);
|
||||
g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
|
||||
g_test_add_func ("/file/copy/progress", test_copy_progress);
|
||||
g_test_add_func ("/file/copy-async-with-closurse", test_copy_async_with_closures);
|
||||
g_test_add_func ("/file/measure", test_measure);
|
||||
g_test_add_func ("/file/measure-async", test_measure_async);
|
||||
g_test_add_func ("/file/load-bytes", test_load_bytes);
|
||||
@ -4045,6 +4233,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/file/writev/async_all-cancellation", test_writev_async_all_cancellation);
|
||||
g_test_add_func ("/file/build-attribute-list-for-copy", test_build_attribute_list_for_copy);
|
||||
g_test_add_func ("/file/move_async", test_move_async);
|
||||
g_test_add_func ("/file/move-async-with-closures", test_move_async_with_closures);
|
||||
g_test_add_func ("/file/query-zero-length-content-type", test_query_zero_length_content_type);
|
||||
g_test_add_func ("/file/query-default-handler-file", test_query_default_handler_file);
|
||||
g_test_add_func ("/file/query-default-handler-file-async", test_query_default_handler_file_async);
|
||||
|
Loading…
Reference in New Issue
Block a user