/* -*- 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 * Copyright (C) 2016 Kalev Lember * * 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 #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); }