diff options
Diffstat (limited to 'src-ng/nautilus-task.c')
-rw-r--r-- | src-ng/nautilus-task.c | 327 |
1 files changed, 243 insertions, 84 deletions
diff --git a/src-ng/nautilus-task.c b/src-ng/nautilus-task.c index de6bdea36..8506648f8 100644 --- a/src-ng/nautilus-task.c +++ b/src-ng/nautilus-task.c @@ -18,150 +18,309 @@ #include "nautilus-task.h" -#include "nautilus-signal-utilities.h" +#include "nautilus-context-scheduler.h" -typedef struct +struct _NautilusTask { + GObject parent_instance; + + NautilusScheduler *scheduler; + + GClosure *closure; GCancellable *cancellable; - GMainContext *context; -} NautilusTaskPrivate; + GError *error; -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (NautilusTask, nautilus_task, - G_TYPE_OBJECT) + GValue result; -enum -{ - PROP_CANCELLABLE = 1, - N_PROPERTIES + GMainContext *context; + GQueue *callbacks; }; -static GParamSpec *properties[N_PROPERTIES] = { NULL }; +G_DEFINE_TYPE (NautilusTask, nautilus_task, G_TYPE_OBJECT) static void -set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) +finalize (GObject *object) { - switch (property_id) + NautilusTask *self; + + self = NAUTILUS_TASK (object); + + if (self->closure != NULL) { - case PROP_CANCELLABLE: - { - NautilusTask *self; - NautilusTaskPrivate *priv; + g_clear_pointer (&self->closure, g_closure_unref); + } + if (self->cancellable != NULL) + { + g_clear_object (&self->cancellable); + } + if (self->error != NULL) + { + g_clear_pointer (&self->error, g_error_free); + } - self = NAUTILUS_TASK (object); - priv = nautilus_task_get_instance_private (self); + g_queue_free (self->callbacks); - if (G_UNLIKELY (priv->cancellable) != NULL) - { - g_clear_object (&priv->cancellable); - } + G_OBJECT_CLASS (nautilus_task_parent_class)->finalize (object); +} - priv->cancellable = g_value_dup_object (value); - } - break; +static void +nautilus_task_class_init (NautilusTaskClass *klass) +{ + GObjectClass *object_class; - default: - { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } - } + object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = finalize; } static void -finalize (GObject *object) +nautilus_task_init (NautilusTask *self) { - NautilusTask *self; - NautilusTaskPrivate *priv; + self->scheduler = nautilus_scheduler_get_default (); + self->cancellable = NULL; + self->error = NULL; + self->context = NULL; + self->callbacks = g_queue_new (); +} - self = NAUTILUS_TASK (object); - priv = nautilus_task_get_instance_private (self); +GMainContext * +nautilus_task_get_main_context (NautilusTask *task) +{ + g_return_val_if_fail (NAUTILUS_IS_TASK (task), NULL); - g_clear_object (&priv->cancellable); - g_clear_pointer (&priv->context, g_main_context_unref); + if (task->context == NULL) + { + return NULL; + } - G_OBJECT_CLASS (nautilus_task_parent_class)->finalize (object); + return g_main_context_ref (task->context); +} + +void +nautilus_task_set_main_context (NautilusTask *task, + GMainContext *context) +{ + g_return_if_fail (NAUTILUS_IS_TASK (task)); + g_return_if_fail (context != NULL); + + if (task->context != NULL) + { + g_main_context_unref (task->context); + } + + task->context = g_main_context_ref (context); } static void -nautilus_task_class_init (NautilusTaskClass *klass) +nautilus_task_add_callback_closure (NautilusTask *task, + GClosure *closure) { - GObjectClass *object_class; + g_queue_push_tail (task->callbacks, g_closure_ref (closure)); +} - object_class = G_OBJECT_CLASS (klass); +void +nautilus_task_add_callback (NautilusTask *task, + NautilusTaskFunc callback, + gpointer user_data) +{ + g_autoptr (GClosure) closure = NULL; - object_class->set_property = set_property; - object_class->finalize = finalize; + g_return_if_fail (NAUTILUS_IS_TASK (task)); + g_return_if_fail (callback != NULL); + + closure = g_cclosure_new (G_CALLBACK (callback), user_data, NULL); - properties[PROP_CANCELLABLE] = - g_param_spec_object ("cancellable", "Cancellable", "Cancellable", - G_TYPE_CANCELLABLE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME); + g_closure_set_marshal (closure, g_cclosure_marshal_VOID__VOID); - g_object_class_install_properties (object_class, N_PROPERTIES, properties); + nautilus_task_add_callback_closure (task, closure); } static void -nautilus_task_init (NautilusTask *self) +invoke_callbacks_iteration (gpointer data) +{ + NautilusTask *task; + g_autoptr (GClosure) closure = NULL; + GValue params = { 0 }; + + task = data; + closure = g_queue_pop_head (task->callbacks); + + g_value_init (¶ms, G_TYPE_OBJECT); + g_value_set_object (¶ms, task); + g_closure_invoke (closure, NULL, 1, ¶ms, NULL); + g_closure_invalidate (closure); + g_value_unset (¶ms); +} + +void +nautilus_task_complete (NautilusTask *task) { - NautilusTaskPrivate *priv; + g_return_if_fail (NAUTILUS_IS_TASK (task)); + + while (g_queue_peek_head (task->callbacks) != NULL) + { + if (task->context != NULL) + { + NautilusScheduler *context_scheduler; - priv = nautilus_task_get_instance_private (self); + context_scheduler = nautilus_context_scheduler_get_for_context (task->context); - priv->context = g_main_context_ref_thread_default (); + nautilus_scheduler_queue (context_scheduler, invoke_callbacks_iteration, task); + } + else + { + invoke_callbacks_iteration (task); + } + } } -GCancellable * -nautilus_task_get_cancellable (NautilusTask *task) +GValue * +nautilus_task_get_result (NautilusTask *task) { - NautilusTaskPrivate *priv; + g_return_val_if_fail (NAUTILUS_IS_TASK (task), NULL); - g_return_val_if_fail (NAUTILUS_TASK (task), NULL); + return &task->result; +} - priv = nautilus_task_get_instance_private (task); +void +nautilus_task_set_result (NautilusTask *task, + GType type, + gpointer result) +{ + g_return_if_fail (NAUTILUS_IS_TASK (task)); + g_return_if_fail (type != G_TYPE_INVALID); + g_return_if_fail (result != NULL); - if (priv->cancellable == NULL) + if (G_VALUE_TYPE (&task->result) != G_TYPE_INVALID) { - return NULL; + g_value_unset (&task->result); } - return g_object_ref (priv->cancellable); + g_value_init (&task->result, type); + g_value_set_instance (&task->result, result); +} + +GError * +nautilus_task_get_error (NautilusTask *task) +{ + GError *error; + + g_return_val_if_fail (NAUTILUS_IS_TASK (task), NULL); + + error = task->error; + task->error = NULL; + + return error; } void -nautilus_task_execute (NautilusTask *task) +nautilus_task_set_error (NautilusTask *task, + GError *error) { - NautilusTaskClass *klass; + g_return_if_fail (NAUTILUS_IS_TASK (task)); + g_return_if_fail (error != NULL); + + task->error = error; +} +void +nautilus_task_set_scheduler (NautilusTask *task, + NautilusScheduler *scheduler) +{ g_return_if_fail (NAUTILUS_IS_TASK (task)); + g_return_if_fail (NAUTILUS_IS_SCHEDULER (scheduler)); - klass = NAUTILUS_TASK_GET_CLASS (task); + g_object_unref (task->scheduler); + + task->scheduler = g_object_ref (scheduler); +} + +static void +nautilus_task_execute (gpointer user_data) +{ + NautilusTask *task; + GValue params = { 0 }; - g_return_if_fail (klass->execute != NULL); + task = user_data; - klass->execute (task); + g_value_init (¶ms, G_TYPE_OBJECT); + g_value_set_object (¶ms, task); + g_closure_invoke (task->closure, NULL, 1, ¶ms, NULL); + g_closure_invalidate (task->closure); + g_clear_pointer (&task->closure, g_closure_unref); + g_value_unset (¶ms); } void -nautilus_task_emit_signal_in_main_context (NautilusTask *task, - guint signal_id, - GQuark detail, - ...) +nautilus_task_run (NautilusTask *task) { - NautilusTaskPrivate *priv; - va_list ap; - g_return_if_fail (NAUTILUS_IS_TASK (task)); - priv = nautilus_task_get_instance_private (task); - va_start (ap, detail); + nautilus_scheduler_queue (task->scheduler, + NAUTILUS_CALLBACK (nautilus_task_execute), + g_object_ref (task)); +} + +GCancellable * +nautilus_task_get_cancellable (NautilusTask *task) +{ + g_return_val_if_fail (NAUTILUS_IS_TASK (task), NULL); + + return g_object_ref (task->cancellable); +} + +NautilusTask * +nautilus_task_new_with_closure (GClosure *closure, + GCancellable *cancellable) +{ + NautilusTask *instance; + + g_return_val_if_fail (closure != NULL, NULL); + if (cancellable != NULL) + { + g_return_val_if_fail (G_IS_CANCELLABLE (cancellable), NULL); + } + + instance = g_object_new (NAUTILUS_TYPE_TASK, NULL); - nautilus_emit_signal_in_main_context_va_list (task, - priv->context, - signal_id, - detail, - ap); + instance->closure = g_closure_ref (closure); + if (cancellable != NULL) + { + instance->cancellable = g_object_ref (cancellable); + } - va_end (ap); + return instance; +} + +/* Would be nice to accept a #GDestroyNotify for @user_data, + * but it’s not a #GClosureNotify, ergo UB. + */ +NautilusTask * +nautilus_task_new_with_func (NautilusTaskFunc func, + gpointer func_data, + GCancellable *cancellable) +{ + g_autoptr (GClosure) closure = NULL; + + g_return_val_if_fail (func != NULL, NULL); + + closure = g_cclosure_new (G_CALLBACK (func), func_data, NULL); + + g_closure_set_marshal (closure, g_cclosure_marshal_VOID__VOID); + + return nautilus_task_new_with_closure (closure, cancellable); +} + +static void +dummy_task_func (NautilusTask *task, + gpointer user_data) +{ + (void) task; + (void) user_data; +} + +NautilusTask * +nautilus_task_new (GCancellable *cancellable) +{ + return nautilus_task_new_with_func (dummy_task_func, NULL, cancellable); } |