238 lines
6.4 KiB
C
238 lines
6.4 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2020 Collabora Ltd.
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
*
|
|
* 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
|
|
*/
|