summaryrefslogtreecommitdiff
path: root/src-ng/nautilus-task.c
diff options
context:
space:
mode:
Diffstat (limited to 'src-ng/nautilus-task.c')
-rw-r--r--src-ng/nautilus-task.c327
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 (&params, G_TYPE_OBJECT);
+ g_value_set_object (&params, task);
+ g_closure_invoke (closure, NULL, 1, &params, NULL);
+ g_closure_invalidate (closure);
+ g_value_unset (&params);
+}
+
+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 (&params, G_TYPE_OBJECT);
+ g_value_set_object (&params, task);
+ g_closure_invoke (task->closure, NULL, 1, &params, NULL);
+ g_closure_invalidate (task->closure);
+ g_clear_pointer (&task->closure, g_closure_unref);
+ g_value_unset (&params);
}
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);
}