/* WirePlumber * * Copyright © 2020 Collabora Ltd. * @author George Kiagiadakis * * SPDX-License-Identifier: MIT */ #include "plugin.h" #include "core.h" #include "log.h" WP_DEFINE_LOCAL_LOG_TOPIC ("wp-plugin") /*! \defgroup wpplugin WpPlugin */ /*! * \struct WpPlugin * * WpPlugin 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 subclass, the plugin inherits WpObject'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::enable() and WpPluginClass::disable(). * For more advanced plugins that need to have more features, you may * implement directly the functions of WpObjectClass and ignore the ones of * WpPluginClass. * * \gproperties * * \gproperty{name, gchar *, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY, * The name of this plugin} */ enum { PROP_0, PROP_NAME, }; typedef struct _WpPluginPrivate WpPluginPrivate; struct _WpPluginPrivate { GQuark name_quark; }; 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; 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)); } 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); } /*! * \brief Looks up a plugin. * * \ingroup 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_core_find_object (core, (GEqualFunc) find_plugin_func, GUINT_TO_POINTER (q)); return p ? WP_PLUGIN (p) : NULL; } /*! * \brief Retreives the name of a plugin. * * \ingroup 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); } /** * \var _WpPluginClass::enable * * \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 \a transition. * * \param self the plugin * \param transition the activation transition */ /** * \var _WpPluginClass::disable * * \brief Disables the plugin. The plugin is required to stop all operations * and release all resources associated with it. * * \param self the plugin */