diff options
Diffstat (limited to '')
-rw-r--r-- | lib/gs-plugin-event.c | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/lib/gs-plugin-event.c b/lib/gs-plugin-event.c new file mode 100644 index 0000000..699e529 --- /dev/null +++ b/lib/gs-plugin-event.c @@ -0,0 +1,453 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * vi:set noexpandtab tabstop=8 shiftwidth=8: + * + * Copyright (C) 2016 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2016 Kalev Lember <klember@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/** + * SECTION:gs-plugin-event + * @title: GsPluginEvent + * @include: gnome-software.h + * @stability: Unstable + * @short_description: Information about a plugin event + * + * These functions provide a way for plugins to tell the UI layer about events + * that may require displaying to the user. Plugins should not assume that a + * specific event is actually shown to the user as it may be ignored + * automatically. + */ + +#include "config.h" + +#include <glib.h> + +#include "gs-enums.h" +#include "gs-plugin-private.h" +#include "gs-plugin-event.h" +#include "gs-plugin-job.h" +#include "gs-utils.h" + +struct _GsPluginEvent +{ + GObject parent_instance; + GsApp *app; + GsApp *origin; + GsPluginAction action; + GsPluginJob *job; /* (owned) (nullable) */ + GError *error; + GsPluginEventFlag flags; + gchar *unique_id; +}; + +G_DEFINE_TYPE (GsPluginEvent, gs_plugin_event, G_TYPE_OBJECT) + +typedef enum { + PROP_APP = 1, + PROP_ORIGIN, + PROP_ACTION, + PROP_JOB, + PROP_ERROR, +} GsPluginEventProperty; + +static GParamSpec *props[PROP_ERROR + 1] = { NULL, }; + +/** + * gs_plugin_event_get_app: + * @event: A #GsPluginEvent + * + * Gets an application that created the event. + * + * Returns: (transfer none): a #GsApp, or %NULL if unset + * + * Since: 3.22 + **/ +GsApp * +gs_plugin_event_get_app (GsPluginEvent *event) +{ + g_return_val_if_fail (GS_IS_PLUGIN_EVENT (event), NULL); + return event->app; +} + +/** + * gs_plugin_event_get_origin: + * @event: A #GsPluginEvent + * + * Gets an origin that created the event. + * + * Returns: (transfer none): a #GsApp, or %NULL if unset + * + * Since: 3.22 + **/ +GsApp * +gs_plugin_event_get_origin (GsPluginEvent *event) +{ + g_return_val_if_fail (GS_IS_PLUGIN_EVENT (event), NULL); + return event->origin; +} + +/** + * gs_plugin_event_get_action: + * @event: A #GsPluginEvent + * + * Gets an action that created the event. + * + * Returns: (transfer none): a #GsPluginAction, e.g. %GS_PLUGIN_ACTION_UPDATE + * + * Since: 3.22 + **/ +GsPluginAction +gs_plugin_event_get_action (GsPluginEvent *event) +{ + g_return_val_if_fail (GS_IS_PLUGIN_EVENT (event), 0); + return event->action; +} + +/** + * gs_plugin_event_get_job: + * @event: A #GsPluginEvent + * + * Gets the job that created the event. + * + * Returns: (transfer none) (nullable): a #GsPluginJob + * + * Since: 42 + **/ +GsPluginJob * +gs_plugin_event_get_job (GsPluginEvent *event) +{ + g_return_val_if_fail (GS_IS_PLUGIN_EVENT (event), NULL); + return event->job; +} + +/** + * gs_plugin_event_get_unique_id: + * @event: A #GsPluginEvent + * + * Gets the unique ID for the event. In most cases (if an app has been set) + * this will just be the actual #GsApp unique-id. In the cases where only error + * has been set a virtual (but plausible) ID will be generated. + * + * Returns: a string, or %NULL for invalid + * + * Since: 3.22 + **/ +const gchar * +gs_plugin_event_get_unique_id (GsPluginEvent *event) +{ + /* just proxy */ + if (event->origin != NULL && + gs_app_get_unique_id (event->origin) != NULL) { + return gs_app_get_unique_id (event->origin); + } + if (event->app != NULL && + gs_app_get_unique_id (event->app) != NULL) { + return gs_app_get_unique_id (event->app); + } + + /* generate from error */ + if (event->error != NULL) { + if (event->unique_id == NULL) { + g_autofree gchar *id = NULL; + id = g_strdup_printf ("%s.error", + gs_plugin_error_to_string (event->error->code)); + event->unique_id = gs_utils_build_unique_id (AS_COMPONENT_SCOPE_UNKNOWN, + AS_BUNDLE_KIND_UNKNOWN, + NULL, + id, + NULL); + } + return event->unique_id; + } + + /* failed */ + return NULL; +} + +/** + * gs_plugin_event_get_kind: + * @event: A #GsPluginEvent + * @flag: A #GsPluginEventFlag, e.g. %GS_PLUGIN_EVENT_FLAG_INVALID + * + * Adds a flag to the event. + * + * Since: 3.22 + **/ +void +gs_plugin_event_add_flag (GsPluginEvent *event, GsPluginEventFlag flag) +{ + g_return_if_fail (GS_IS_PLUGIN_EVENT (event)); + event->flags |= flag; +} + +/** + * gs_plugin_event_set_kind: + * @event: A #GsPluginEvent + * @flag: A #GsPluginEventFlag, e.g. %GS_PLUGIN_EVENT_FLAG_INVALID + * + * Removes a flag from the event. + * + * Since: 3.22 + **/ +void +gs_plugin_event_remove_flag (GsPluginEvent *event, GsPluginEventFlag flag) +{ + g_return_if_fail (GS_IS_PLUGIN_EVENT (event)); + event->flags &= ~flag; +} + +/** + * gs_plugin_event_has_flag: + * @event: A #GsPluginEvent + * @flag: A #GsPluginEventFlag, e.g. %GS_PLUGIN_EVENT_FLAG_INVALID + * + * Finds out if the event has a specific flag. + * + * Returns: %TRUE if the flag is set + * + * Since: 3.22 + **/ +gboolean +gs_plugin_event_has_flag (GsPluginEvent *event, GsPluginEventFlag flag) +{ + g_return_val_if_fail (GS_IS_PLUGIN_EVENT (event), FALSE); + return ((event->flags & flag) > 0); +} + +/** + * gs_plugin_event_get_error: + * @event: A #GsPluginEvent + * + * Gets the event error. + * + * Returns: a #GError, or %NULL for unset + * + * Since: 3.22 + **/ +const GError * +gs_plugin_event_get_error (GsPluginEvent *event) +{ + return event->error; +} + +static void +gs_plugin_event_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GsPluginEvent *self = GS_PLUGIN_EVENT (object); + + switch ((GsPluginEventProperty) prop_id) { + case PROP_APP: + g_value_set_object (value, self->app); + break; + case PROP_ORIGIN: + g_value_set_object (value, self->origin); + break; + case PROP_ACTION: + g_value_set_enum (value, self->action); + break; + case PROP_JOB: + g_value_set_object (value, self->job); + break; + case PROP_ERROR: + g_value_set_boxed (value, self->error); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gs_plugin_event_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GsPluginEvent *self = GS_PLUGIN_EVENT (object); + + switch ((GsPluginEventProperty) prop_id) { + case PROP_APP: + /* Construct only. */ + g_assert (self->app == NULL); + self->app = g_value_dup_object (value); + g_object_notify_by_pspec (object, props[prop_id]); + break; + case PROP_ORIGIN: + /* Construct only. */ + g_assert (self->origin == NULL); + self->origin = g_value_dup_object (value); + g_object_notify_by_pspec (object, props[prop_id]); + break; + case PROP_ACTION: + /* Construct only. */ + g_assert (self->action == GS_PLUGIN_ACTION_UNKNOWN); + self->action = g_value_get_enum (value); + g_object_notify_by_pspec (object, props[prop_id]); + break; + case PROP_JOB: + /* Construct only. */ + g_assert (self->job == NULL); + self->job = g_value_dup_object (value); + g_object_notify_by_pspec (object, props[prop_id]); + break; + case PROP_ERROR: + /* Construct only. */ + g_assert (self->error == NULL); + self->error = g_value_dup_boxed (value); + if (self->error) { + /* Just in case the caller left there any D-Bus remote error notes */ + g_dbus_error_strip_remote_error (self->error); + } + g_object_notify_by_pspec (object, props[prop_id]); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gs_plugin_event_dispose (GObject *object) +{ + GsPluginEvent *event = GS_PLUGIN_EVENT (object); + + g_clear_object (&event->app); + g_clear_object (&event->origin); + g_clear_object (&event->job); + + G_OBJECT_CLASS (gs_plugin_event_parent_class)->dispose (object); +} + +static void +gs_plugin_event_finalize (GObject *object) +{ + GsPluginEvent *event = GS_PLUGIN_EVENT (object); + + g_clear_error (&event->error); + g_free (event->unique_id); + + G_OBJECT_CLASS (gs_plugin_event_parent_class)->finalize (object); +} + +static void +gs_plugin_event_class_init (GsPluginEventClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gs_plugin_event_get_property; + object_class->set_property = gs_plugin_event_set_property; + object_class->dispose = gs_plugin_event_dispose; + object_class->finalize = gs_plugin_event_finalize; + + /** + * GsPluginEvent:app: (nullable) + * + * The application (or source, or whatever component) that caused the + * event to be created. + * + * Since: 42 + */ + props[PROP_APP] = + g_param_spec_object ("app", "App", + "The application (or source, or whatever component) that caused the event to be created.", + GS_TYPE_APP, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GsPluginEvent:origin: (nullable) + * + * The origin that caused the event to be created. + * + * Since: 42 + */ + props[PROP_ORIGIN] = + g_param_spec_object ("origin", "Origin", + "The origin that caused the event to be created.", + GS_TYPE_APP, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GsPluginEvent:action: + * + * The action that caused the event to be created. + * + * Since: 42 + */ + props[PROP_ACTION] = + g_param_spec_enum ("action", "Action", + "The action that caused the event to be created.", + GS_TYPE_PLUGIN_ACTION, GS_PLUGIN_ACTION_UNKNOWN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GsPluginEvent:job: (nullable) + * + * The job that caused the event to be created. + * + * Since: 42 + */ + props[PROP_JOB] = + g_param_spec_object ("job", "Job", + "The job that caused the event to be created.", + GS_TYPE_PLUGIN_JOB, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GsPluginEvent:error: (nullable) + * + * The error the event is reporting. + * + * Since: 42 + */ + props[PROP_ERROR] = + g_param_spec_boxed ("error", "Error", + "The error the event is reporting.", + G_TYPE_ERROR, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, G_N_ELEMENTS (props), props); +} + +static void +gs_plugin_event_init (GsPluginEvent *event) +{ +} + +/** + * gs_plugin_event_new: + * @first_property_name: the name of the first property + * @...: the value of the first property, followed by zero or more pairs of + * property name/value pairs, then %NULL + * + * Creates a new event. + * + * The arguments are as for g_object_new(): property name/value pairs to set + * the properties of the event. + * + * Returns: (transfer full): A newly allocated #GsPluginEvent + * + * Since: 42 + **/ +GsPluginEvent * +gs_plugin_event_new (const gchar *first_property_name, + ...) +{ + GsPluginEvent *event; + va_list args; + + va_start (args, first_property_name); + event = GS_PLUGIN_EVENT (g_object_new_valist (GS_TYPE_PLUGIN_EVENT, first_property_name, args)); + va_end (args); + + return GS_PLUGIN_EVENT (event); +} |