Commit f61e2929 authored by George Kiagiadakis's avatar George Kiagiadakis
Browse files

plugin: inherit from WpObject

* use the activate/deactivate system from WpObject,
  which allows async activation and error reporting
* drop 'module' property, use 'core' from WpObject
parent 596990d7
......@@ -20,14 +20,12 @@
enum {
PROP_0,
PROP_NAME,
PROP_MODULE,
};
typedef struct _WpPluginPrivate WpPluginPrivate;
struct _WpPluginPrivate
{
GQuark name_quark;
GWeakRef module;
};
/**
......@@ -38,38 +36,22 @@ struct _WpPluginPrivate
*
* 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 #WpPluginClass.activate() after all modules have been loaded,
* 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.
*/
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpPlugin, wp_plugin, G_TYPE_OBJECT)
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpPlugin, wp_plugin, WP_TYPE_OBJECT)
static void
wp_plugin_init (WpPlugin * self)
{
WpPluginPrivate *priv = wp_plugin_get_instance_private (self);
g_weak_ref_init (&priv->module, NULL);
}
static void
wp_plugin_dispose (GObject * object)
{
WpPlugin *self = WP_PLUGIN (object);
wp_plugin_deactivate (self);
G_OBJECT_CLASS (wp_plugin_parent_class)->dispose (object);
}
static void
wp_plugin_finalize (GObject * object)
{
WpPlugin *self = WP_PLUGIN (object);
WpPluginPrivate *priv = wp_plugin_get_instance_private (self);
g_weak_ref_clear (&priv->module);
G_OBJECT_CLASS (wp_plugin_parent_class)->finalize (object);
}
static void
......@@ -83,9 +65,6 @@ wp_plugin_set_property (GObject * object, guint property_id,
case PROP_NAME:
priv->name_quark = g_quark_from_string (g_value_get_string (value));
break;
case PROP_MODULE:
g_weak_ref_set (&priv->module, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
......@@ -103,25 +82,81 @@ wp_plugin_get_property (GObject * object, guint property_id,
case PROP_NAME:
g_value_set_string (value, g_quark_to_string (priv->name_quark));
break;
case PROP_MODULE:
g_value_take_object (value, g_weak_ref_get (&priv->module));
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 @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->dispose = wp_plugin_dispose;
object_class->finalize = wp_plugin_finalize;
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:
* The name of this plugin.
......@@ -131,16 +166,6 @@ wp_plugin_class_init (WpPluginClass * klass)
g_param_spec_string ("name", "name",
"The name of this plugin", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
/**
* WpPlugin:module:
* The module that created this plugin.
* Implementations should initialize this in the constructor.
*/
g_object_class_install_property (object_class, PROP_MODULE,
g_param_spec_object ("module", "module",
"The module that owns this plugin", WP_TYPE_MODULE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
/**
......@@ -152,7 +177,7 @@ wp_plugin_class_init (WpPluginClass * klass)
void
wp_plugin_register (WpPlugin * plugin)
{
g_autoptr (WpCore) core = wp_plugin_get_core (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);
......@@ -204,65 +229,22 @@ wp_plugin_get_name (WpPlugin * self)
}
/**
* wp_plugin_get_module:
* @self: the plugin
*
* Returns: (transfer full): the module associated with this plugin
*/
WpModule *
wp_plugin_get_module (WpPlugin * self)
{
g_return_val_if_fail (WP_IS_PLUGIN (self), NULL);
WpPluginPrivate *priv = wp_plugin_get_instance_private (self);
return g_weak_ref_get (&priv->module);
}
/**
* wp_plugin_get_core:
* @self: the plugin
*
* Returns: (transfer full): the core associated with this plugin
*/
WpCore *
wp_plugin_get_core (WpPlugin * self)
{
g_autoptr (WpModule) module = wp_plugin_get_module (self);
return module ? wp_module_get_core (module) : NULL;
}
/**
* wp_plugin_activate: (virtual activate)
* WpPluginClass.enable:
* @self: the plugin
* @transition: the activation transition
*
* Activates the plugin. The plugin is required to start any operations only
* 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 @transition.
*/
void
wp_plugin_activate (WpPlugin * self)
{
g_return_if_fail (WP_IS_PLUGIN (self));
g_return_if_fail (WP_PLUGIN_GET_CLASS (self)->activate);
wp_info_object (self, "activating plugin '%s'", wp_plugin_get_name (self));
WP_PLUGIN_GET_CLASS (self)->activate (self);
}
/**
* wp_plugin_deactivate: (virtual deactivate)
* WpPluginClass.disable:
* @self: the plugin
*
* Deactivates the plugin. The plugin is required to stop all operations and
* Disables the plugin. The plugin is required to stop all operations and
* release all resources associated with it.
*/
void
wp_plugin_deactivate (WpPlugin * self)
{
g_return_if_fail (WP_IS_PLUGIN (self));
g_return_if_fail (WP_PLUGIN_GET_CLASS (self)->deactivate);
wp_info_object (self, "deactivating plugin '%s'", wp_plugin_get_name (self));
WP_PLUGIN_GET_CLASS (self)->deactivate (self);
}
......@@ -9,10 +9,20 @@
#ifndef __WIREPLUMBER_PLUGIN_H__
#define __WIREPLUMBER_PLUGIN_H__
#include "module.h"
#include "object.h"
G_BEGIN_DECLS
/**
* WpPluginFeatures:
* @WP_PLUGIN_FEATURE_ENABLED: enables the plugin
*
* Flags to be used as #WpObjectFeatures for #WpPlugin subclasses.
*/
typedef enum { /*< flags >*/
WP_PLUGIN_FEATURE_ENABLED = (1 << 0),
} WpPluginFeatures;
/**
* WP_TYPE_PLUGIN:
*
......@@ -20,19 +30,17 @@ G_BEGIN_DECLS
*/
#define WP_TYPE_PLUGIN (wp_plugin_get_type ())
WP_API
G_DECLARE_DERIVABLE_TYPE (WpPlugin, wp_plugin, WP, PLUGIN, GObject)
G_DECLARE_DERIVABLE_TYPE (WpPlugin, wp_plugin, WP, PLUGIN, WpObject)
/**
* WpPluginClass:
* @activate: See wp_plugin_activate()
* @deactivate: See wp_plugin_deactivate()
*/
struct _WpPluginClass
{
GObjectClass parent_class;
WpObjectClass parent_class;
void (*activate) (WpPlugin * self);
void (*deactivate) (WpPlugin * self);
void (*enable) (WpPlugin * self, WpTransition * transition);
void (*disable) (WpPlugin * self);
};
WP_API
......@@ -44,18 +52,6 @@ WpPlugin * wp_plugin_find (WpCore * core, const gchar * plugin_name);
WP_API
const gchar * wp_plugin_get_name (WpPlugin * self);
WP_API
WpModule * wp_plugin_get_module (WpPlugin * self);
WP_API
WpCore * wp_plugin_get_core (WpPlugin * self);
WP_API
void wp_plugin_activate (WpPlugin * self);
WP_API
void wp_plugin_deactivate (WpPlugin * self);
G_END_DECLS
#endif
......@@ -40,10 +40,10 @@ client_added (WpObjectManager * om, WpClient *client, WpClientPermissions * self
}
static void
wp_client_permissions_activate (WpPlugin * plugin)
wp_client_permissions_enable (WpPlugin * plugin, WpTransition * transition)
{
WpClientPermissions * self = WP_CLIENT_PERMISSIONS (plugin);
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
g_return_if_fail (core);
......@@ -51,14 +51,14 @@ wp_client_permissions_activate (WpPlugin * plugin)
wp_object_manager_add_interest (self->om, WP_TYPE_CLIENT, NULL);
wp_object_manager_request_object_features (self->om, WP_TYPE_CLIENT,
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL);
g_signal_connect (self->om, "object-added", (GCallback) client_added, self);
wp_core_install_object_manager (core, self->om);
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_client_permissions_deactivate (WpPlugin * plugin)
wp_client_permissions_disable (WpPlugin * plugin)
{
WpClientPermissions * self = WP_CLIENT_PERMISSIONS (plugin);
......@@ -70,8 +70,8 @@ wp_client_permissions_class_init (WpClientPermissionsClass * klass)
{
WpPluginClass *plugin_class = (WpPluginClass *) klass;
plugin_class->activate = wp_client_permissions_activate;
plugin_class->deactivate = wp_client_permissions_deactivate;
plugin_class->enable = wp_client_permissions_enable;
plugin_class->disable = wp_client_permissions_disable;
}
WP_PLUGIN_EXPORT void
......@@ -79,6 +79,6 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
{
wp_plugin_register (g_object_new (wp_client_permissions_get_type (),
"name", "client-permissions",
"module", module,
"core", core,
NULL));
}
......@@ -62,7 +62,7 @@ timeout_save_callback (gpointer p)
static void
timeout_save_default_endpoints (WpDefaultMetadata *self, guint dir, guint ms)
{
g_autoptr (WpCore) core = wp_plugin_get_core (WP_PLUGIN (self));
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
g_return_if_fail (core);
/* Clear the current timeout callback */
......@@ -290,7 +290,7 @@ static void
on_metadata_added (WpObjectManager *om, WpMetadata *metadata, gpointer d)
{
WpDefaultMetadata * self = WP_DEFAULT_METADATA (d);
g_autoptr (WpCore) core = wp_plugin_get_core (WP_PLUGIN (self));
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
g_return_if_fail (core);
......@@ -314,10 +314,10 @@ on_metadata_added (WpObjectManager *om, WpMetadata *metadata, gpointer d)
}
static void
wp_default_metadata_activate (WpPlugin * plugin)
wp_default_metadata_enable (WpPlugin * plugin, WpTransition * transition)
{
WpDefaultMetadata * self = WP_DEFAULT_METADATA (plugin);
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
g_return_if_fail (core);
......@@ -330,10 +330,12 @@ wp_default_metadata_activate (WpPlugin * plugin)
g_signal_connect_object (self->metadatas_om, "object-added",
G_CALLBACK (on_metadata_added), self, 0);
wp_core_install_object_manager (core, self->metadatas_om);
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_default_metadata_deactivate (WpPlugin * plugin)
wp_default_metadata_disable (WpPlugin * plugin)
{
WpDefaultMetadata * self = WP_DEFAULT_METADATA (plugin);
......@@ -396,8 +398,8 @@ wp_default_metadata_class_init (WpDefaultMetadataClass * klass)
object_class->finalize = wp_default_metadata_finalize;
plugin_class->activate = wp_default_metadata_activate;
plugin_class->deactivate = wp_default_metadata_deactivate;
plugin_class->enable = wp_default_metadata_enable;
plugin_class->disable = wp_default_metadata_disable;
}
WP_PLUGIN_EXPORT void
......@@ -405,6 +407,6 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
{
wp_plugin_register (g_object_new (wp_default_metadata_get_type (),
"name", "default-metadata",
"module", module,
"core", core,
NULL));
}
......@@ -94,7 +94,7 @@ timeout_save_profiles (WpDefaultProfile *self, guint ms)
{
WpDefaultProfilePrivate *priv =
wp_default_profile_get_instance_private (self);
g_autoptr (WpCore) core = wp_plugin_get_core (WP_PLUGIN (self));
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
g_return_if_fail (core);
g_return_if_fail (priv->profiles);
......@@ -251,9 +251,9 @@ on_device_added (WpObjectManager *om, WpPipewireObject *proxy, gpointer d)
}
static void
wp_default_profile_activate (WpPlugin * plugin)
wp_default_profile_enable (WpPlugin * plugin, WpTransition * transition)
{
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
WpDefaultProfile *self = WP_DEFAULT_PROFILE (plugin);
WpDefaultProfilePrivate *priv =
wp_default_profile_get_instance_private (self);
......@@ -266,10 +266,12 @@ wp_default_profile_activate (WpPlugin * plugin)
g_signal_connect_object (priv->devices_om, "object-added",
G_CALLBACK (on_device_added), self, 0);
wp_core_install_object_manager (core, priv->devices_om);
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_default_profile_deactivate (WpPlugin * plugin)
wp_default_profile_disable (WpPlugin * plugin)
{
WpDefaultProfile *self = WP_DEFAULT_PROFILE (plugin);
WpDefaultProfilePrivate *priv =
......@@ -317,8 +319,8 @@ wp_default_profile_class_init (WpDefaultProfileClass * klass)
WpPluginClass *plugin_class = (WpPluginClass *) klass;
object_class->finalize = wp_default_profile_finalize;
plugin_class->activate = wp_default_profile_activate;
plugin_class->deactivate = wp_default_profile_deactivate;
plugin_class->enable = wp_default_profile_enable;
plugin_class->disable = wp_default_profile_disable;
klass->get_profile = wp_default_profile_get_profile;
......@@ -335,6 +337,6 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
{
wp_plugin_register (g_object_new (wp_default_profile_get_type (),
"name", STATE_NAME,
"module", module,
"core", core,
NULL));
}
......@@ -132,10 +132,10 @@ on_plugin_added (WpObjectManager *om, WpPlugin *plugin, gpointer d)
}
static void
wp_device_activation_activate (WpPlugin * plugin)
wp_device_activation_enable (WpPlugin * plugin, WpTransition * transition)
{
WpDeviceActivation *self = WP_DEVICE_ACTIVATION (plugin);
g_autoptr (WpCore) core = wp_plugin_get_core (WP_PLUGIN (self));
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
/* Create the plugin object manager */
self->plugins_om = wp_object_manager_new ();
......@@ -154,10 +154,12 @@ wp_device_activation_activate (WpPlugin * plugin)
g_signal_connect_object (self->devices_om, "object-added",
G_CALLBACK (on_device_added), self, 0);
wp_core_install_object_manager (core, self->devices_om);
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_device_activation_deactivate (WpPlugin * plugin)
wp_device_activation_disable (WpPlugin * plugin)
{
WpDeviceActivation *self = WP_DEVICE_ACTIVATION (plugin);
......@@ -176,8 +178,8 @@ wp_device_activation_class_init (WpDeviceActivationClass * klass)
{
WpPluginClass *plugin_class = (WpPluginClass *) klass;
plugin_class->activate = wp_device_activation_activate;
plugin_class->deactivate = wp_device_activation_deactivate;
plugin_class->enable = wp_device_activation_enable;
plugin_class->disable = wp_device_activation_disable;
}
......@@ -186,6 +188,6 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
{
wp_plugin_register (g_object_new (wp_device_activation_get_type (),
"name", "device-activation",
"module", module,
"core", core,
NULL));
}
......@@ -90,7 +90,7 @@ static void
wp_lua_scripting_plugin_init_lua_ctx (WpConfigParser * engine, lua_State * L,
WpLuaScriptingPlugin * self)
{
g_autoptr (WpCore) core = wp_plugin_get_core (WP_PLUGIN (self));
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
lua_pushliteral (L, "wireplumber_core");
lua_pushlightuserdata (L, core);
......@@ -104,10 +104,10 @@ wp_lua_scripting_plugin_init_lua_ctx (WpConfigParser * engine, lua_State * L,
}
static void
wp_lua_scripting_plugin_activate (WpPlugin * plugin)
wp_lua_scripting_plugin_enable (WpPlugin * plugin, WpTransition * transition)
{
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin);
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
g_autoptr (WpConfigParser) engine = NULL;
self->config = wp_configuration_get_instance (core);
......@@ -118,7 +118,9 @@ wp_lua_scripting_plugin_activate (WpPlugin * plugin)
PW_KEY_APP_NAME, "WirePlumber (export)",
NULL));
if (!wp_core_connect (self->export_core)) {
wp_warning_object (self, "failed to connect export core");
wp_transition_return_error (transition, g_error_new (
WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
"failed to connect export core"));
return;
}
......@@ -132,10 +134,11 @@ wp_lua_scripting_plugin_activate (WpPlugin * plugin)
G_CALLBACK (wp_lua_scripting_plugin_init_lua_ctx), self, 0);
wp_configuration_reload (self->config, self->config_ext);
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_lua_scripting_plugin_deactivate (WpPlugin * plugin)
wp_lua_scripting_plugin_disable (WpPlugin * plugin)
{
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin);
......@@ -156,8 +159,8 @@ wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass)
object_class->set_property = wp_lua_scripting_plugin_set_property;
object_class->get_property = wp_lua_scripting_plugin_get_property;
plugin_class->activate = wp_lua_scripting_plugin_activate;
plugin_class->deactivate = wp_lua_scripting_plugin_deactivate;
plugin_class->enable = wp_lua_scripting_plugin_enable;
plugin_class->disable = wp_lua_scripting_plugin_disable;
g_object_class_install_property(object_class, PROP_PROFILE,
g_param_spec_string ("profile", "profile",
......@@ -177,7 +180,7 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
wp_plugin_register (g_object_new (wp_lua_scripting_plugin_get_type (),
"name", "lua-scripting",
"module", module,
"core", core,
"profile", profile,
NULL));
}
......@@ -27,27 +27,34 @@ wp_metadata_plugin_init (WpMetadataPlugin * self)
static void
on_metadata_activated (GObject * obj, GAsyncResult * res, gpointer user_data)
{
WpTransition * transition = WP_TRANSITION (user_data);
WpMetadataPlugin * self = wp_transition_get_source_object (transition);
g_autoptr (GError) error = NULL;
if (!wp_object_activate_finish (WP_OBJECT (obj), res, &error)) {
wp_warning_object (user_data, "failed to activate WpImplMetadata: %s",
error->message);
g_clear_object (&self->metadata);
g_prefix_error (&error, "Failed to activate WpImplMetadata: ");
wp_transition_return_error (transition, g_steal_pointer (&error));
return;
}
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_metadata_plugin_activate (WpPlugin * plugin)
wp_metadata_plugin_enable (WpPlugin * plugin, WpTransition * transition)
{
WpMetadataPlugin * self = WP_METADATA_PLUGIN (plugin);
g_autoptr (WpCore) core = wp_plugin_get_core (plugin);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
g_return_if_fail (core);
self->metadata = wp_impl_metadata_new (core);