diff options
Diffstat (limited to 'src/mm-sleep-context.c')
-rw-r--r-- | src/mm-sleep-context.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/mm-sleep-context.c b/src/mm-sleep-context.c new file mode 100644 index 00000000..69a9da22 --- /dev/null +++ b/src/mm-sleep-context.c @@ -0,0 +1,165 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright 2025 Dan Williams <dan@ioncontrol.co> + */ + +#include <gio/gio.h> + +#include "mm-utils.h" + +#include "mm-sleep-context.h" + +static void log_object_iface_init (MMLogObjectInterface *iface); + +G_DEFINE_TYPE_EXTENDED (MMSleepContext, mm_sleep_context, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_LOG_OBJECT, log_object_iface_init)) + +struct _MMSleepContextPrivate { + GTask *task; + guint timeout_id; +}; + +enum { + DONE, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +/*****************************************************************************/ + +static gchar * +log_object_build_id (MMLogObject *_self) +{ + return g_strdup_printf ("sleep-context"); +} + +/*****************************************************************************/ + +static void +timeout_cleanup (MMSleepContext *self) +{ + if (self->priv->timeout_id) + g_source_remove (self->priv->timeout_id); + self->priv->timeout_id = 0; +} + +void +mm_sleep_context_complete (MMSleepContext *self, + GError *error) +{ + timeout_cleanup (self); + + if (error) { + mm_obj_dbg (self, "completing with error '%s'", error->message); + g_task_return_error (self->priv->task, error); + } else { + mm_obj_dbg (self, "completing with success"); + g_task_return_boolean (self->priv->task, TRUE); + } + g_clear_object (&self->priv->task); +} + +static gboolean +operation_timeout (MMSleepContext *self) +{ + mm_obj_dbg (self, "timeout"); + mm_sleep_context_complete (self, + g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_TIMED_OUT, + "timeout waiting for sleep preparation to complete")); + return G_SOURCE_REMOVE; +} + +static void +operation_ready (MMSleepContext *self, + GAsyncResult *res) +{ + g_autoptr(GError) error = NULL; + gboolean success; + + mm_obj_dbg (self, "notifying listeners task is done"); + + success = g_task_propagate_boolean (G_TASK (res), &error); + g_assert (success || error); + g_signal_emit (self, signals[DONE], 0, error); +} + +/*****************************************************************************/ + +MMSleepContext * +mm_sleep_context_new (guint timeout_seconds) +{ + MMSleepContext *self; + + self = MM_SLEEP_CONTEXT (g_object_new (MM_TYPE_SLEEP_CONTEXT, NULL)); + self->priv->task = g_task_new (self, + NULL, + (GAsyncReadyCallback)operation_ready, + NULL); + self->priv->timeout_id = g_timeout_add_seconds (timeout_seconds, + (GSourceFunc)operation_timeout, + self); + mm_obj_dbg (self, "new context with %d second timeout", timeout_seconds); + + return self; +} + +static void +log_object_iface_init (MMLogObjectInterface *iface) +{ + iface->build_id = log_object_build_id; +} + +static void +mm_sleep_context_init (MMSleepContext *self) +{ + /* Initialize opaque pointer to private data */ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + MM_TYPE_SLEEP_CONTEXT, + MMSleepContextPrivate); +} + +static void +dispose (GObject *object) +{ + MMSleepContext *self = MM_SLEEP_CONTEXT (object); + + timeout_cleanup (self); + /* Task must always be completed and cleared before disposal */ + g_assert (self->priv->task == NULL); + + G_OBJECT_CLASS (mm_sleep_context_parent_class)->dispose (object); +} + +static void +mm_sleep_context_class_init (MMSleepContextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMSleepContextPrivate)); + + /* Virtual methods */ + object_class->dispose = dispose; + + signals[DONE] = g_signal_new (MM_SLEEP_CONTEXT_DONE, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MMSleepContextClass, done), + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_generic, + G_TYPE_NONE, + 1, + G_TYPE_ERROR); +} |