/* WirePlumber * * Copyright © 2020 Collabora Ltd. * @author George Kiagiadakis * * SPDX-License-Identifier: MIT */ /*! * @file plugin.c */ #define G_LOG_DOMAIN "wp-plugin" #include "plugin.h" #include "log.h" #include "private/registry.h" /*! * @memberof WpPlugin * * @props @b name * * @code * "name" gchar * * @endcode * * The name of this plugin. Implementations should initialize this in the constructor. * * Flags : Read / Write / Construct Only */ enum { PROP_0, PROP_NAME, }; typedef struct _WpPluginPrivate WpPluginPrivate; struct _WpPluginPrivate { GQuark name_quark; }; /*! * @struct WpPlugin * @section plugin_section Plugins * * @brief [WpPlugin](@ref plugin_section) is a base class for objects that * provide functionality to the WirePlumber daemon. * * Typically, a plugin is created within a module and then registered to * make it available for use by the daemon. The daemon is responsible for * calling wp_object_activate() on it after all modules have been loaded, * the core is connected and the initial discovery of global objects is * done. * * Being a [WpObject](@ref object_section) subclass, the plugin inherits * [WpObject](@ref object_section)'s activation system. * For most implementations, there is only need for activating one * feature, %WP_PLUGIN_FEATURE_ENABLED, and this can be done by implementing * only [WpPluginClass](@ref plugin_class_section).[enable](@ref plugin_class_enable_section)() and * [WpPluginClass](@ref plugin_class_section).[disable](@ref plugin_class_disable_section)(). * For more advanced plugins that need to have more features, you may implement directly the * functions of [WpObjectClass](@ref object_class_section) and ignore the ones of * [WpPluginClass](@ref plugin_class_section). * */ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpPlugin, wp_plugin, WP_TYPE_OBJECT) static void wp_plugin_init (WpPlugin * self) { } static void wp_plugin_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { WpPlugin *self = WP_PLUGIN (object); WpPluginPrivate *priv = wp_plugin_get_instance_private (self); switch (property_id) { case PROP_NAME: priv->name_quark = g_quark_from_string (g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void wp_plugin_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { WpPlugin *self = WP_PLUGIN (object); WpPluginPrivate *priv = wp_plugin_get_instance_private (self); switch (property_id) { case PROP_NAME: g_value_set_string (value, g_quark_to_string (priv->name_quark)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static WpObjectFeatures wp_plugin_get_supported_features (WpObject * self) { return WP_PLUGIN_FEATURE_ENABLED; } enum { STEP_ENABLE = WP_TRANSITION_STEP_CUSTOM_START, }; static guint wp_plugin_activate_get_next_step (WpObject * object, WpFeatureActivationTransition * transition, guint step, WpObjectFeatures missing) { /* we only support ENABLED, so this is the only feature that can be in @em missing */ g_return_val_if_fail (missing == WP_PLUGIN_FEATURE_ENABLED, WP_TRANSITION_STEP_ERROR); return STEP_ENABLE; } static void wp_plugin_activate_execute_step (WpObject * object, WpFeatureActivationTransition * transition, guint step, WpObjectFeatures missing) { switch (step) { case STEP_ENABLE: { WpPlugin *self = WP_PLUGIN (object); wp_info_object (self, "enabling plugin '%s'", wp_plugin_get_name (self)); g_return_if_fail (WP_PLUGIN_GET_CLASS (self)->enable); WP_PLUGIN_GET_CLASS (self)->enable (self, WP_TRANSITION (transition)); break; } case WP_TRANSITION_STEP_ERROR: break; default: g_assert_not_reached (); } } static void wp_plugin_deactivate (WpObject * object, WpObjectFeatures features) { if (features & WP_PLUGIN_FEATURE_ENABLED) { WpPlugin *self = WP_PLUGIN (object); wp_info_object (self, "disabling plugin '%s'", wp_plugin_get_name (self)); if (WP_PLUGIN_GET_CLASS (self)->disable) WP_PLUGIN_GET_CLASS (self)->disable (self); wp_object_update_features (WP_OBJECT (self), 0, WP_PLUGIN_FEATURE_ENABLED); } } static void wp_plugin_class_init (WpPluginClass * klass) { GObjectClass * object_class = (GObjectClass *) klass; WpObjectClass * wpobject_class = (WpObjectClass *) klass; object_class->set_property = wp_plugin_set_property; object_class->get_property = wp_plugin_get_property; wpobject_class->get_supported_features = wp_plugin_get_supported_features; wpobject_class->activate_get_next_step = wp_plugin_activate_get_next_step; wpobject_class->activate_execute_step = wp_plugin_activate_execute_step; wpobject_class->deactivate = wp_plugin_deactivate; /* * WpPlugin:name: * @brief The name of this plugin. * Implementations should initialize this in the constructor. */ g_object_class_install_property (object_class, PROP_NAME, g_param_spec_string ("name", "name", "The name of this plugin", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } /*! * @memberof WpPlugin * @param plugin: (transfer full): the plugin * * @brief Registers the plugin to its associated core, making it available for use */ void wp_plugin_register (WpPlugin * plugin) { g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin)); g_return_if_fail (WP_IS_CORE (core)); wp_registry_register_object (wp_core_get_registry (core), plugin); } static gboolean find_plugin_func (gpointer plugin, gpointer name_quark) { if (!WP_IS_PLUGIN (plugin)) return FALSE; WpPluginPrivate *priv = wp_plugin_get_instance_private (plugin); return priv->name_quark == GPOINTER_TO_UINT (name_quark); } /*! * @memberof WpPlugin * @param core: the core * @param plugin_name: the lookup name * * @returns (transfer full) (nullable): the plugin matching the lookup name */ WpPlugin * wp_plugin_find (WpCore * core, const gchar * plugin_name) { g_return_val_if_fail (WP_IS_CORE (core), NULL); GQuark q = g_quark_try_string (plugin_name); if (q == 0) return NULL; GObject *p = wp_registry_find_object (wp_core_get_registry (core), (GEqualFunc) find_plugin_func, GUINT_TO_POINTER (q)); return p ? WP_PLUGIN (p) : NULL; } /*! * @memberof WpPlugin * @param self: the plugin * * @returns the name of this plugin */ const gchar * wp_plugin_get_name (WpPlugin * self) { g_return_val_if_fail (WP_IS_PLUGIN (self), NULL); WpPluginPrivate *priv = wp_plugin_get_instance_private (self); return g_quark_to_string (priv->name_quark); } /** * WpPluginClass::enable: * * @section plugin_class_enable_section enable * * @param self: the plugin * @param transition: the activation transition * * @brief Enables the plugin. The plugin is required to start any operations only * when this method is called and not before. * * When enabling the plugin is done, you must call wp_object_update_features() * with %WP_PLUGIN_FEATURE_ENABLED marked as activated, or return an error * on @em transition. */ /** * WpPluginClass::disable: * * @section plugin_class_disable_section disable * * @param self: the plugin * * Disables the plugin. The plugin is required to stop all operations and * release all resources associated with it. */