From c61d1e4245f437bebf29a0f268e600b0bd7fc870 Mon Sep 17 00:00:00 2001 From: Julian Bouzas Date: Thu, 9 Feb 2023 13:11:14 -0500 Subject: [PATCH] component-loader: make wp_core_load_component() API asynchronous This change completely refactors the way components are loaded in wireplumber: - The module_init() function must return a GObject now. This object is either a WpPlugin or a WpSiFactory in the current modules. - When the component loader initializes a module, it automatically registers the WpPlugin or WpSiFactory with their respective methods. There is no need to register the WpPlugin or WpSiFactory in the module now. - The wp_core_load_component() API has been refactored to be asynchronows. This allows the component loader to automatically activate WpPlugin objects, and therefore allows the application to directly get the WpPlugin without having to find it. This simplifies a lot of things. - The 'ifexists' and 'nofail' component flags now work even if the respective WpPlugin could not be activated. - The code that loads components in main.c has also been simplified a lot, and the option to load dangling components has also been removed. --- lib/wp/component-loader.c | 116 ++++- lib/wp/component-loader.h | 5 +- lib/wp/core.h | 9 +- modules/module-default-nodes-api.c | 11 +- modules/module-file-monitor-api.c | 11 +- modules/module-logind.c | 11 +- modules/module-lua-scripting/api/require.c | 53 +- modules/module-lua-scripting/module.c | 107 ++-- modules/module-lua-scripting/script.c | 2 +- modules/module-mixer-api.c | 11 +- modules/module-portal-permissionstore.c | 6 +- modules/module-reserve-device/plugin.c | 5 +- modules/module-settings.c | 8 +- modules/module-si-audio-adapter.c | 5 +- modules/module-si-audio-virtual.c | 5 +- modules/module-si-node.c | 5 +- modules/module-si-standard-link.c | 5 +- modules/module-standard-event-source.c | 11 +- src/main.c | 536 +++++++-------------- src/tools/wpctl.c | 48 +- src/tools/wpexec.c | 45 +- tests/modules/file-monitor.c | 34 +- tests/modules/reserve-device.c | 74 +-- tests/modules/si-audio-adapter.c | 16 +- tests/modules/si-audio-virtual.c | 21 +- tests/modules/si-node.c | 16 +- tests/modules/si-standard-link.c | 20 +- tests/script-tester.c | 26 +- 28 files changed, 519 insertions(+), 703 deletions(-) diff --git a/lib/wp/component-loader.c b/lib/wp/component-loader.c index 4172c849..45a63d1c 100644 --- a/lib/wp/component-loader.c +++ b/lib/wp/component-loader.c @@ -32,7 +32,7 @@ */ #define WP_MODULE_INIT_SYMBOL "wireplumber__module_init" -typedef gboolean (*WpModuleInitFunc) (WpCore *, GVariant *, GError **); +typedef GObject *(*WpModuleInitFunc) (WpCore *, GVariant *, GError **); G_DEFINE_ABSTRACT_TYPE (WpComponentLoader, wp_component_loader, WP_TYPE_PLUGIN) @@ -46,7 +46,7 @@ wp_component_loader_class_init (WpComponentLoaderClass * klass) { } -static gboolean +static GObject * load_module (WpCore * core, const gchar * module_name, GVariant * args, GError ** error) { @@ -64,7 +64,7 @@ load_module (WpCore * core, const gchar * module_name, if (!gmodule) { g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED, "Failed to open module %s: %s", module_path, g_module_error ()); - return FALSE; + return NULL; } if (!g_module_symbol (gmodule, WP_MODULE_INIT_SYMBOL, &module_init)) { @@ -72,7 +72,7 @@ load_module (WpCore * core, const gchar * module_name, "Failed to locate symbol " WP_MODULE_INIT_SYMBOL " in %s", module_path); g_module_close (gmodule); - return FALSE; + return NULL; } return ((WpModuleInitFunc) module_init) (core, args, error); @@ -98,13 +98,28 @@ wp_component_loader_find (WpCore * core, const gchar * type) return c ? WP_COMPONENT_LOADER (c) : NULL; } -static gboolean +static void wp_component_loader_load (WpComponentLoader * self, const gchar * component, - const gchar * type, GVariant * args, GError ** error) + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data) { - g_return_val_if_fail (WP_IS_COMPONENT_LOADER (self), FALSE); - return WP_COMPONENT_LOADER_GET_CLASS (self)->load (self, component, type, - args, error); + g_return_if_fail (WP_IS_COMPONENT_LOADER (self)); + WP_COMPONENT_LOADER_GET_CLASS (self)->load (self, component, type, + args, callback, data); +} + +static void +on_object_loaded (WpObject *object, GAsyncResult *res, gpointer data) +{ + g_autoptr (GTask) task = G_TASK (data); + g_autoptr (GError) error = NULL; + + if (!wp_object_activate_finish (object, res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_task_return_pointer (task, g_object_ref (object), g_object_unref); } /*! @@ -121,25 +136,80 @@ wp_component_loader_load (WpComponentLoader * self, const gchar * component, * \param type the type of the component * \param args (transfer floating)(nullable): additional arguments for the component, * usually a dict or a string - * \param error (out) (optional): return location for errors, or NULL to ignore - * \returns TRUE if loaded, FALSE if there was an error + * \param callback (scope async): the callback to call when the operation is done + * \param data (closure): data to pass to \a callback */ -gboolean +void wp_core_load_component (WpCore * self, const gchar * component, - const gchar * type, GVariant * args, GError ** error) + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data) { g_autoptr (GVariant) args_ref = args ? g_variant_ref_sink (args) : NULL; + g_autoptr (GTask) task = NULL; + g_autoptr (WpComponentLoader) c = NULL; - if (!g_strcmp0 (type, "module")) - return load_module (self, component, args_ref, error); - else { - g_autoptr (WpComponentLoader) c = wp_component_loader_find (self, type); - if (c) - return wp_component_loader_load (c, component, type, args, error); - else { - g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT, - "No component loader was found for components of type '%s'", type); - return FALSE; + /* Special case for "module" component type */ + if (g_str_equal (type, "module")) { + task = g_task_new (self, NULL, callback, data); + g_autoptr (GError) error = NULL; + g_autoptr (GObject) o = NULL; + + /* load Module */ + o = load_module (self, component, args_ref, &error); + if (!o) { + g_task_return_error (task, g_steal_pointer (&error)); + return; } + + if (WP_IS_OBJECT (o)) { + /* WpObject needs to be activated */ + if (WP_IS_PLUGIN (o)) + wp_plugin_register (WP_PLUGIN (g_object_ref (o))); + wp_object_activate (WP_OBJECT (o), WP_OBJECT_FEATURES_ALL, NULL, + (GAsyncReadyCallback) on_object_loaded, g_object_ref (task)); + return; + } else if (WP_IS_SI_FACTORY (o)) { + /* WpSiFactory doesn't need to be activated */ + wp_si_factory_register (self, WP_SI_FACTORY (g_object_ref (o))); + g_task_return_pointer (task, g_object_ref (o), g_object_unref); + return; + } + + g_task_return_new_error (task, WP_DOMAIN_LIBRARY, + WP_LIBRARY_ERROR_INVALID_ARGUMENT, + "Invalid module object for component %s", component); + return; } + + /* Otherwise find a component loader for that type and load the component */ + c = wp_component_loader_find (self, type); + if (!c) { + task = g_task_new (self, NULL, callback, data); + g_task_return_new_error (task, WP_DOMAIN_LIBRARY, + WP_LIBRARY_ERROR_INVALID_ARGUMENT, + "No component loader was found for components of type '%s'", type); + return; + } + + wp_component_loader_load (c, component, type, args, callback, data); +} + +/*! + * \brief Finishes the operation started by wp_core_load_component(). + * This is meant to be called in the callback that was passed to that method. + * + * + * \ingroup wpcomponentloader + * \param self the component loader object + * \param res the async result + * \param error (out) (optional): the operation's error, if it occurred + * \returns (transfer full): The loaded component object, or NULL if an + * error happened. + */ +GObject * +wp_core_load_component_finish (WpCore * self, GAsyncResult * res, + GError ** error) +{ + gpointer o = g_task_propagate_pointer (G_TASK (res), error); + return o ? g_object_ref (G_OBJECT (o)) : NULL; } diff --git a/lib/wp/component-loader.h b/lib/wp/component-loader.h index c9bcc9e0..3c6267eb 100644 --- a/lib/wp/component-loader.h +++ b/lib/wp/component-loader.h @@ -28,8 +28,9 @@ struct _WpComponentLoaderClass gboolean (*supports_type) (WpComponentLoader * self, const gchar * type); - gboolean (*load) (WpComponentLoader * self, const gchar * component, - const gchar * type, GVariant * args, GError ** error); + void (*load) (WpComponentLoader * self, const gchar * component, + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data); /*< private >*/ WP_PADDING(6) diff --git a/lib/wp/core.h b/lib/wp/core.h index 37997a8c..d62b51ba 100644 --- a/lib/wp/core.h +++ b/lib/wp/core.h @@ -48,8 +48,13 @@ WP_API gchar *wp_core_get_vm_type (WpCore *self); WP_API -gboolean wp_core_load_component (WpCore * self, const gchar * component, - const gchar * type, GVariant * args, GError ** error); +void wp_core_load_component (WpCore * self, const gchar * component, + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data); + +WP_API +GObject * wp_core_load_component_finish (WpCore * self, GAsyncResult * res, + GError ** error); /* Connection */ diff --git a/modules/module-default-nodes-api.c b/modules/module-default-nodes-api.c index 8800f67b..212baebf 100644 --- a/modules/module-default-nodes-api.c +++ b/modules/module-default-nodes-api.c @@ -304,12 +304,11 @@ wp_default_nodes_api_class_init (WpDefaultNodesApiClass * klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_default_nodes_api_get_type (), - "name", "default-nodes-api", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_default_nodes_api_get_type (), + "name", "default-nodes-api", + "core", core, + NULL)); } diff --git a/modules/module-file-monitor-api.c b/modules/module-file-monitor-api.c index bd2c9fcf..8f797cd6 100644 --- a/modules/module-file-monitor-api.c +++ b/modules/module-file-monitor-api.c @@ -201,12 +201,11 @@ wp_file_monitor_api_class_init (WpFileMonitorApiClass * klass) G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_file_monitor_api_get_type (), - "name", "file-monitor-api", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_file_monitor_api_get_type (), + "name", "file-monitor-api", + "core", core, + NULL)); } diff --git a/modules/module-logind.c b/modules/module-logind.c index 7724479e..9ed41449 100644 --- a/modules/module-logind.c +++ b/modules/module-logind.c @@ -131,12 +131,11 @@ wp_logind_class_init (WpLogindClass * klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_logind_get_type (), - "name", NAME, - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_logind_get_type (), + "name", NAME, + "core", core, + NULL)); } diff --git a/modules/module-lua-scripting/api/require.c b/modules/module-lua-scripting/api/require.c index 520bd139..e4ae2e6c 100644 --- a/modules/module-lua-scripting/api/require.c +++ b/modules/module-lua-scripting/api/require.c @@ -17,8 +17,7 @@ struct _WpRequireApiTransition }; enum { - STEP_LOAD_MODULES = WP_TRANSITION_STEP_CUSTOM_START, - STEP_ACTIVATE_PLUGINS, + STEP_LOAD_PLUGINS = WP_TRANSITION_STEP_CUSTOM_START, }; G_DECLARE_FINAL_TYPE (WpRequireApiTransition, wp_require_api_transition, @@ -47,23 +46,24 @@ wp_require_api_transition_get_next_step (WpTransition * transition, guint step) WpRequireApiTransition *self = WP_REQUIRE_API_TRANSITION (transition); switch (step) { - case WP_TRANSITION_STEP_NONE: return STEP_LOAD_MODULES; - case STEP_LOAD_MODULES: return STEP_ACTIVATE_PLUGINS; - case STEP_ACTIVATE_PLUGINS: + case WP_TRANSITION_STEP_NONE: return STEP_LOAD_PLUGINS; + case STEP_LOAD_PLUGINS: return (self->pending_plugins > 0) ? - STEP_ACTIVATE_PLUGINS : WP_TRANSITION_STEP_NONE; + STEP_LOAD_PLUGINS : WP_TRANSITION_STEP_NONE; default: g_return_val_if_reached (WP_TRANSITION_STEP_ERROR); } } static void -on_plugin_activated (WpObject * p, GAsyncResult * res, +on_plugin_loaded (WpCore * core, GAsyncResult * res, WpRequireApiTransition *self) { + g_autoptr (GObject) o = NULL; GError *error = NULL; - if (!wp_object_activate_finish (p, res, &error)) { + o = wp_core_load_component_finish (core, res, &error); + if (!o) { wp_transition_return_error (WP_TRANSITION (self), error); return; } @@ -79,49 +79,24 @@ wp_require_api_transition_execute_step (WpTransition * transition, guint step) WpCore *core = wp_transition_get_source_object (transition); switch (step) { - case STEP_LOAD_MODULES: - { + case STEP_LOAD_PLUGINS: + wp_debug_object (self, "Loading plugins..."); + for (guint i = 0; i < self->apis->len; i++) { const gchar *api_name = g_ptr_array_index (self->apis, i); g_autoptr (WpPlugin) plugin = wp_plugin_find (core, api_name); if (!plugin) { - GError *error = NULL; gchar module_name[50]; - g_snprintf (module_name, sizeof (module_name), "libwireplumber-module-%s", api_name); - if (!wp_core_load_component (core, module_name, "module", NULL, &error)) { - wp_transition_return_error (transition, error); - return; - } - - plugin = wp_plugin_find (core, api_name); - if (!plugin) { - wp_transition_return_error (transition, g_error_new ( - WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT, - "API '%s' was not found in module '%s'", api_name, module_name)); - return; - } + self->pending_plugins++; + wp_core_load_component (core, module_name, "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, self); } } wp_transition_advance (transition); break; - } - - case STEP_ACTIVATE_PLUGINS: - wp_debug_object (self, "Activating plugins..."); - - for (guint i = 0; i < self->apis->len; i++) { - const gchar *api_name = g_ptr_array_index (self->apis, i); - g_autoptr (WpPlugin) plugin = wp_plugin_find (core, api_name); - - self->pending_plugins++; - wp_object_activate (WP_OBJECT (plugin), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, self); - } - wp_transition_advance (transition); - break; case WP_TRANSITION_STEP_ERROR: break; diff --git a/modules/module-lua-scripting/module.c b/modules/module-lua-scripting/module.c index e95a9996..1b9a28b5 100644 --- a/modules/module-lua-scripting/module.c +++ b/modules/module-lua-scripting/module.c @@ -18,7 +18,6 @@ struct _WpLuaScriptingPlugin { WpComponentLoader parent; - GPtrArray *scripts; /* element-type: WpPlugin* */ lua_State *L; }; @@ -90,17 +89,6 @@ G_DEFINE_TYPE (WpLuaScriptingPlugin, wp_lua_scripting_plugin, static void wp_lua_scripting_plugin_init (WpLuaScriptingPlugin * self) { - self->scripts = g_ptr_array_new_with_free_func (g_object_unref); -} - -static void -wp_lua_scripting_plugin_finalize (GObject * object) -{ - WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (object); - - g_clear_pointer (&self->scripts, g_ptr_array_unref); - - G_OBJECT_CLASS (wp_lua_scripting_plugin_parent_class)->finalize (object); } static void @@ -129,14 +117,6 @@ wp_lua_scripting_plugin_enable (WpPlugin * plugin, WpTransition * transition) wp_lua_scripting_enable_package_searcher (self->L); wplua_enable_sandbox (self->L, WP_LUA_SANDBOX_ISOLATE_ENV); - /* register scripts that were queued in for loading */ - for (guint i = 0; i < self->scripts->len; i++) { - WpPlugin *script = g_ptr_array_index (self->scripts, i); - g_object_set (script, "lua-engine", self->L, NULL); - wp_plugin_register (g_object_ref (script)); - } - g_ptr_array_set_size (self->scripts, 0); - wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0); } @@ -144,6 +124,7 @@ static void wp_lua_scripting_plugin_disable (WpPlugin * plugin) { WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin); + g_clear_pointer (&self->L, wplua_unref); } @@ -165,7 +146,6 @@ find_script (const gchar * script, WpCore *core) g_file_test (script, G_FILE_TEST_IS_REGULAR)) return g_strdup (script); - return wp_find_file (WP_LOOKUP_DIR_ENV_DATA | WP_LOOKUP_DIR_ENV_TEST_SRCDIR | WP_LOOKUP_DIR_XDG_CONFIG_HOME | @@ -174,71 +154,79 @@ find_script (const gchar * script, WpCore *core) script, "scripts"); } -static gboolean +static void +on_script_loaded (WpObject *object, GAsyncResult *res, gpointer data) +{ + g_autoptr (GTask) task = G_TASK (data); + g_autoptr (GError) error = NULL; + + if (!wp_object_activate_finish (object, res, &error)) { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_task_return_pointer (task, g_object_ref (object), g_object_unref); +} + +static void wp_lua_scripting_plugin_load (WpComponentLoader * cl, const gchar * component, - const gchar * type, GVariant * args, GError ** error) + const gchar * type, GVariant * args, GAsyncReadyCallback callback, + gpointer data) { WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (cl); - g_autoptr (WpCore) core = NULL; + g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (cl)); + g_autoptr (GTask) task = task = g_task_new (core, NULL, callback, data); g_autofree gchar *filepath = NULL; g_autofree gchar *pluginname = NULL; g_autoptr (WpPlugin) script = NULL; + /* make sure the component loader is activated */ + if (!self->L) { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Lua script component loader cannot load Lua scripts if not enabled"); + return; + } + + /* make sure the type is supported */ if (!g_str_equal (type, "script/lua")) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Could not load script '%s' as its type is not 'script/lua'", component); - return FALSE; - } - - core = wp_object_get_core (WP_OBJECT (cl)); - - if (g_file_test (component, G_FILE_TEST_EXISTS)) { - /* dangling components come with full path */ - g_autofree gchar *filename = g_path_get_basename (component); - filepath = g_strdup (component); - pluginname = g_strdup_printf ("script:%s", filename); - } else { - filepath = find_script (component, core); - pluginname = g_strdup_printf ("script:%s", component); + return; } + /* find the script */ + filepath = find_script (component, core); if (!filepath) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Could not locate script '%s'", component); - return FALSE; + return; } + pluginname = g_strdup_printf ("script:%s", component); + script = g_object_new (WP_TYPE_LUA_SCRIPT, "core", core, "name", pluginname, + "lua-engine", self->L, "filename", filepath, "arguments", args, NULL); - if (self->L) { - wp_debug_object (core, "loading script(%s) plugin name(%s)", - filepath, pluginname); - g_object_set (script, "lua-engine", self->L, NULL); - wp_plugin_register (g_steal_pointer (&script)); - } else { - /* keep in a list and delay registering until the plugin is enabled */ - wp_debug ("queuing script %s", filepath); - g_ptr_array_add (self->scripts, g_steal_pointer (&script)); - } + /* register the script */ + wp_plugin_register (g_object_ref (script)); - return TRUE; + /* enable script */ + wp_object_activate (WP_OBJECT (script), WP_OBJECT_FEATURES_ALL, NULL, + (GAsyncReadyCallback) on_script_loaded, g_object_ref (task)); } static void wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass) { - GObjectClass *object_class = (GObjectClass *) klass; WpPluginClass *plugin_class = (WpPluginClass *) klass; WpComponentLoaderClass *cl_class = (WpComponentLoaderClass *) klass; - object_class->finalize = wp_lua_scripting_plugin_finalize; - plugin_class->enable = wp_lua_scripting_plugin_enable; plugin_class->disable = wp_lua_scripting_plugin_disable; @@ -246,12 +234,11 @@ wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass) cl_class->load = wp_lua_scripting_plugin_load; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_lua_scripting_plugin_get_type (), - "name", "lua-scripting", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_lua_scripting_plugin_get_type (), + "name", "lua-scripting", + "core", core, + NULL)); } diff --git a/modules/module-lua-scripting/script.c b/modules/module-lua-scripting/script.c index 6a4826e8..b4f715a9 100644 --- a/modules/module-lua-scripting/script.c +++ b/modules/module-lua-scripting/script.c @@ -272,7 +272,7 @@ wp_lua_script_class_init (WpLuaScriptClass * klass) g_object_class_install_property (object_class, PROP_LUA_ENGINE, g_param_spec_pointer ("lua-engine", "lua-engine", "lua-engine", - G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_FILENAME, g_param_spec_string ("filename", "filename", "filename", NULL, diff --git a/modules/module-mixer-api.c b/modules/module-mixer-api.c index 5d37c9fd..9000fb5a 100644 --- a/modules/module-mixer-api.c +++ b/modules/module-mixer-api.c @@ -614,12 +614,11 @@ wp_mixer_api_class_init (WpMixerApiClass * klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_mixer_api_get_type (), - "name", "mixer-api", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_mixer_api_get_type (), + "name", "mixer-api", + "core", core, + NULL)); } diff --git a/modules/module-portal-permissionstore.c b/modules/module-portal-permissionstore.c index c4098747..b320e6db 100644 --- a/modules/module-portal-permissionstore.c +++ b/modules/module-portal-permissionstore.c @@ -302,12 +302,12 @@ wp_portal_permissionstore_plugin_class_init ( G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_VARIANT); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_portal_permissionstore_plugin_get_type(), + return G_OBJECT (g_object_new ( + wp_portal_permissionstore_plugin_get_type(), "name", "portal-permissionstore", "core", core, NULL)); - return TRUE; } diff --git a/modules/module-reserve-device/plugin.c b/modules/module-reserve-device/plugin.c index aba709da..e1000f8d 100644 --- a/modules/module-reserve-device/plugin.c +++ b/modules/module-reserve-device/plugin.c @@ -264,12 +264,11 @@ wp_reserve_device_plugin_class_init (WpReserveDevicePluginClass * klass) } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_reserve_device_plugin_get_type (), + return G_OBJECT (g_object_new (wp_reserve_device_plugin_get_type (), "name", "reserve-device", "core", core, NULL)); - return TRUE; } diff --git a/modules/module-settings.c b/modules/module-settings.c index 1ece400c..56690c96 100644 --- a/modules/module-settings.c +++ b/modules/module-settings.c @@ -336,18 +336,16 @@ wp_settings_plugin_class_init (WpSettingsPluginClass * klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { const gchar *metadata_name = "sm-settings"; - if (args) - metadata_name = g_variant_get_string(args, NULL); + metadata_name = g_variant_get_string (args, NULL); - wp_plugin_register (g_object_new (wp_settings_plugin_get_type (), + return G_OBJECT (g_object_new (wp_settings_plugin_get_type (), "name", "settings", "core", core, "metadata-name", metadata_name, NULL)); - return TRUE; } diff --git a/modules/module-si-audio-adapter.c b/modules/module-si-audio-adapter.c index 6fe67de6..b41c8af4 100644 --- a/modules/module-si-audio-adapter.c +++ b/modules/module-si-audio-adapter.c @@ -777,10 +777,9 @@ si_audio_adapter_linkable_init (WpSiLinkableInterface * iface) iface->get_ports = si_audio_adapter_get_ports; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME, + return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, si_audio_adapter_get_type ())); - return TRUE; } diff --git a/modules/module-si-audio-virtual.c b/modules/module-si-audio-virtual.c index 25fdbd90..01f2f8be 100644 --- a/modules/module-si-audio-virtual.c +++ b/modules/module-si-audio-virtual.c @@ -355,10 +355,9 @@ si_audio_virtual_adapter_init (WpSiAdapterInterface * iface) iface->set_ports_format_finish = si_audio_virtual_set_ports_format_finish; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME, + return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, si_audio_virtual_get_type ())); - return TRUE; } diff --git a/modules/module-si-node.c b/modules/module-si-node.c index 8879c1f2..7ce23363 100644 --- a/modules/module-si-node.c +++ b/modules/module-si-node.c @@ -219,10 +219,9 @@ si_node_linkable_init (WpSiLinkableInterface * iface) iface->get_ports = si_node_get_ports; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME, + return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, si_node_get_type ())); - return TRUE; } diff --git a/modules/module-si-standard-link.c b/modules/module-si-standard-link.c index 2da155d9..1a04631f 100644 --- a/modules/module-si-standard-link.c +++ b/modules/module-si-standard-link.c @@ -775,10 +775,9 @@ si_standard_link_link_init (WpSiLinkInterface * iface) iface->get_in_item = si_standard_link_get_in_item; } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_si_factory_register (core, wp_si_factory_new_simple (SI_FACTORY_NAME, + return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, si_standard_link_get_type ())); - return TRUE; } diff --git a/modules/module-standard-event-source.c b/modules/module-standard-event-source.c index df2c61f1..a3114ab0 100644 --- a/modules/module-standard-event-source.c +++ b/modules/module-standard-event-source.c @@ -449,12 +449,11 @@ wp_standard_event_source_class_init (WpStandardEventSourceClass * klass) NULL, NULL, NULL, G_TYPE_NONE, 1, TYPE_RESCAN_CONTEXT); } -WP_PLUGIN_EXPORT gboolean +WP_PLUGIN_EXPORT GObject * wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) { - wp_plugin_register (g_object_new (wp_standard_event_source_get_type (), - "name", "standard-event-source", - "core", core, - NULL)); - return TRUE; + return G_OBJECT (g_object_new (wp_standard_event_source_get_type (), + "name", "standard-event-source", + "core", core, + NULL)); } diff --git a/src/main.c b/src/main.c index adedea14..43794bf5 100644 --- a/src/main.c +++ b/src/main.c @@ -36,6 +36,49 @@ static GOptionEntry entries[] = { NULL } }; +struct _ComponentData +{ + gchar *name; + gchar *type; + gint priority; + gint flags; + WpSpaJson *deps; +}; +typedef struct _ComponentData ComponentData; + +static gint +component_cmp_func (const ComponentData *a, const ComponentData *b) +{ + return b->priority - a->priority; +} + +static gint +component_equal_func (const ComponentData *a, ComponentData * b) +{ + return + g_str_equal (a->name, b->name) && g_str_equal (a->type, b->type) ? 0 : 1; +} + +static void +component_data_free (ComponentData *self) +{ + g_clear_pointer (&self->name, g_free); + g_clear_pointer (&self->type, g_free); + g_clear_pointer (&self->deps, wp_spa_json_unref); + g_slice_free (ComponentData, self); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ComponentData, component_data_free) + +enum +{ + NO_FAIL = 0x1, + IF_EXISTS = 0x2 +}; + +static void +on_plugin_loaded (WpCore *core, GAsyncResult *res, gpointer user_data); + /*** WpInitTransition ***/ struct _WpInitTransition @@ -43,6 +86,7 @@ struct _WpInitTransition WpTransition parent; WpObjectManager *om; GList *components; + ComponentData *curr_component; }; enum { @@ -78,203 +122,101 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step) } } -typedef struct _component_data component_data; - -struct _component_data +static gboolean +component_meets_dependencies (WpCore *core, ComponentData *comp) { - gchar *name; - gchar *type; - gint priority; - gint flags; - WpSpaJson *deps; -}; + g_autoptr (WpConf) conf = NULL; + g_autoptr (WpIterator) it = NULL; + g_auto (GValue) item = G_VALUE_INIT; -static gint -component_cmp_func (const component_data *a, const component_data *b) -{ - return b->priority - a->priority; -} + if (!comp->deps) + return TRUE; -static void -component_unref (component_data *self) -{ - g_free (self->name); - g_free (self->type); - g_clear_pointer (&self->deps, wp_spa_json_unref); - g_slice_free (component_data, self); -} - -G_DEFINE_AUTOPTR_CLEANUP_FUNC (component_data, component_unref) - -static gint -is_component_present (const component_data *listed_cmpnt, - const gchar *new_cmpnt_name) -{ - return !g_str_equal (listed_cmpnt->name, new_cmpnt_name); -} - -enum -{ - NO_FAIL = 0x1, - IF_EXISTS = 0x2 -}; - -static gchar * -extract_base_name (const gchar *filepath) -{ - gchar *basename = g_path_get_basename (filepath); - - if (!basename) - return NULL; - - if (g_str_has_prefix (basename, "libwireplumber-module-")) { - /* strip the file extension for modules */ - basename [strlen (basename) - strlen (".so")] = '\0'; - return basename; - } else if (g_str_has_suffix (basename, ".lua")) - return basename; - else - return NULL; -} - -static gchar * -extract_plugin_name (gchar *name) -{ - if (g_file_test (name, G_FILE_TEST_EXISTS)) { - /* dangling components */ - name = extract_base_name (name); + /* Note that we consider the dependency valid by default if it is not + * found in the settings configuration section */ + conf = wp_conf_get_instance (core); + it = wp_spa_json_new_iterator (comp->deps); + for (; wp_iterator_next (it, &item); g_value_unset (&item)) { + WpSpaJson *dep = g_value_get_boxed (&item); + g_autofree gchar *dep_str = wp_spa_json_parse_string (dep); + gboolean value = wp_conf_get_value_boolean (conf, + "wireplumber.settings", dep_str, TRUE); + if (!value) + return FALSE; } - if (g_str_has_prefix (name, "libwireplumber-module-")) - return g_strdup (name + strlen ("libwireplumber-module-")); - else - return g_strdup_printf ("script:%s", name); + + return TRUE; } -static void -on_plugin_activated (WpObject *p, GAsyncResult *res, WpInitTransition *self); - -static int -load_enable_component (WpInitTransition *self, GError **error) +static gboolean +load_enable_components (WpInitTransition *self) { WpCore *core = wp_transition_get_source_object (WP_TRANSITION (self)); - GList *comps = self->components; - GList *lcomp = g_list_first (comps); - while (lcomp) { - component_data *comp = (component_data *) lcomp->data; - g_autofree gchar *plugin_name = NULL; - g_autoptr (WpPlugin) plugin = NULL; + while (self->components) { + self->curr_component = (ComponentData *) self->components->data; + g_autoptr (GError) error = NULL; - if (comp->deps) { - g_autoptr (WpConf) conf = wp_conf_get_instance (core); - g_autoptr (WpIterator) it = wp_spa_json_new_iterator (comp->deps); - g_auto (GValue) item = G_VALUE_INIT; - gboolean deps_met = TRUE; + /* Advance */ + self->components = g_list_next (self->components); - /* Note that we consider the dependency valid by default if it is not - * found in the settings */ - for (; wp_iterator_next (it, &item); g_value_unset (&item)) { - WpSpaJson *dep = g_value_get_boxed (&item); - g_autofree gchar *dep_str = wp_spa_json_parse_string (dep); - gboolean value = wp_conf_get_value_boolean (conf, - "wireplumber.settings", dep_str, TRUE); - if (!value) { - deps_met = FALSE; - wp_info (".. deps(%s) not met for component(%s), skip loading it", - dep_str, comp->name); - break; - } - } - if (!deps_met) { - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - self->components = comps; - lcomp = g_list_first (comps); - continue; - } - } - - wp_debug (".. loading component(%s) type(%s) priority(%d) flags(%x)", - comp->name, comp->type, comp->priority, comp->flags); - - g_autoptr (GError) load_error = NULL; - if (!wp_core_load_component (core, comp->name, comp->type, NULL, - &load_error)) { - wp_warning (".. error in loading component (%s)", load_error->message); - if ((load_error->code == G_FILE_ERROR_NOENT) || - (load_error->code == G_FILE_ERROR_ACCES)) { - - if (comp->flags & IF_EXISTS) { - wp_warning (".. \"ifexists\" flag set, ignore the failure"); - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - lcomp = g_list_first (comps); - self->components = comps; - continue; - } else if (comp->flags & NO_FAIL) { - wp_warning (".. \"nofail\" flag set, ignore the failure"); - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - lcomp = g_list_first (comps); - self->components = comps; - continue; - } - } - g_propagate_error (error, g_steal_pointer (&load_error)); - - return -EINVAL; + /* Skip component if its dependencies are not met */ + if (!component_meets_dependencies (core, self->curr_component)) { + wp_info ("... skipping comp '%s' as its dependencies are not met", + self->curr_component->name); + continue; } - /* get handle to corresponding plugin & activate it */ - plugin_name = extract_plugin_name (comp->name); - plugin = wp_plugin_find (core, plugin_name); - if (!plugin) { - g_autoptr (WpSiFactory) si = wp_si_factory_find (core, plugin_name); - if (si) { - /* si factory modules register factories they need not be activated */ - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - lcomp = g_list_first (comps); - self->components = comps; - wp_debug (".. enabled si module(%s)", comp->name); - continue; - } else { - wp_warning (".. unable to find (%s) plugin", plugin_name); - g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED, - "unable to find %s plugin", plugin_name); - return -EINVAL; - } - } - wp_debug (".. enabling component(%s) plugin name(%s)", comp->name, - plugin_name); - - comps = g_list_delete_link (comps, g_steal_pointer (&lcomp)); - self->components = comps; - wp_object_activate_closure (WP_OBJECT (plugin), WP_OBJECT_FEATURES_ALL, - NULL, g_cclosure_new_object (G_CALLBACK (on_plugin_activated), - G_OBJECT (self))); - return 1; + /* Load the component */ + wp_debug ("... loading comp '%s' ('%s') with priority '%d' and flags '%x'", + self->curr_component->name, self->curr_component->type, + self->curr_component->priority, self->curr_component->flags); + wp_core_load_component (core, self->curr_component->name, + self->curr_component->type, NULL, + (GAsyncReadyCallback) on_plugin_loaded, self); + return FALSE; } - return 0; + + self->curr_component = NULL; + return TRUE; } static void -on_plugin_activated (WpObject *p, GAsyncResult *res, WpInitTransition *self) +on_plugin_loaded (WpCore *core, GAsyncResult *res, gpointer data) { + WpInitTransition *self = data; + g_autoptr (GObject) o = NULL; g_autoptr (GError) error = NULL; - int ret = 0; - if (!wp_object_activate_finish (p, res, &error)) { - wp_transition_return_error (WP_TRANSITION (self), g_steal_pointer (&error)); + g_return_if_fail (self->curr_component); + + o = wp_core_load_component_finish (core, res, &error); + if (!o) { + if (self->curr_component->flags & IF_EXISTS && + error->code == G_FILE_ERROR_ISDIR) { + wp_info ("skipping component '%s' with 'ifexists' flag because its " + "file does not exist", self->curr_component->name); + goto next; + } else if (self->curr_component->flags & NO_FAIL) { + wp_info ("skipping component '%s' with 'nofail' flag because of " + "loading error: %s", self->curr_component->name, error->message); + goto next; + } + + wp_transition_return_error (WP_TRANSITION (self), g_error_new ( + WP_DOMAIN_DAEMON, WP_EXIT_SOFTWARE, + "failed to activate component '%s': %s", self->curr_component->name, + error->message)); return; } - wp_debug (".. enabled plugin %s", wp_plugin_get_name (WP_PLUGIN (p))); - ret = load_enable_component (self, &error); - if (ret < 0) { - wp_transition_return_error (WP_TRANSITION (self), g_steal_pointer (&error)); - } - else if (ret == 0) - { - wp_debug (".. loading components successful"); + wp_debug ("successfully enabled plugin %s", + wp_plugin_get_name (WP_PLUGIN (o))); + +next: + /* load and enable the rest of components */ + if (load_enable_components (self)) wp_transition_advance (WP_TRANSITION (self)); - } } static void @@ -290,88 +232,66 @@ check_media_session (WpObjectManager * om, WpInitTransition *self) wp_transition_advance (WP_TRANSITION (self)); } -struct data { - WpTransition *transition; - int count; - GList *components; -}; - static gint -pick_default_component_priority (const char *name) +pick_default_component_priority (const char *type) { - if (g_str_has_suffix (name, ".so")) + if (g_str_equal (type, "module")) /* regular module default priority */ return 110; - else if (g_str_has_suffix (name, ".lua")) + else if (g_str_equal (type, "script/lua")) /* Lua Script default priority */ return 100; return 100; } -static char * -pick_component_type (const char *name) +static void +append_json_components (GList **list, WpSpaJson *json) { - if (g_str_has_suffix (name, ".so")) - return g_strdup ("module"); - else if (g_str_has_suffix (name, ".lua")) - return g_strdup ("script/lua"); - - return NULL; -} - -static int -do_parse_json_components (void *data, const char *location, const char *section, - const char *str, size_t len) -{ - struct data *d = data; - WpTransition *transition = d->transition; - g_autoptr (WpSpaJson) json = NULL; g_autoptr (WpIterator) it = NULL; g_auto (GValue) item = G_VALUE_INIT; - json = wp_spa_json_new_from_stringn (str, len); - if (!wp_spa_json_is_array (json)) { - wp_transition_return_error (transition, g_error_new ( - WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, - "wireplumber.components is not a JSON array")); - return -EINVAL; + wp_warning ("components section is not a JSON array, skipping..."); + return; } it = wp_spa_json_new_iterator (json); for (; wp_iterator_next (it, &item); g_value_unset (&item)) { WpSpaJson *cjson = g_value_get_boxed (&item); - g_autoptr (component_data) component = g_slice_new0 (component_data); + g_autoptr (ComponentData) comp = g_slice_new0 (ComponentData); g_autoptr (WpSpaJson) deps = NULL; g_autoptr (WpSpaJson) flags = NULL; - /* name and type are mandatory tags */ + /* Parse name and type (mandatory) */ if (!wp_spa_json_is_object (cjson) || !wp_spa_json_object_get (cjson, - "name", "s", &component->name, - "type", "s", &component->type, + "name", "s", &comp->name, + "type", "s", &comp->type, NULL)) { - wp_transition_return_error (transition, g_error_new ( - WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, - "component must have both a 'name' and a 'type'")); - return -EINVAL; + wp_warning ("component must have both a 'name' and a 'type'"); + component_data_free (comp); + continue; } - if (!wp_spa_json_object_get (cjson, "priority", "i", &component->priority, + /* Parse priority (optional) */ + if (!wp_spa_json_object_get (cjson, "priority", "i", &comp->priority, NULL)) - component->priority = pick_default_component_priority (component->name); + comp->priority = pick_default_component_priority (comp->type); + /* Parse deps (optional) */ if (wp_spa_json_object_get (cjson, "deps", "J", &deps, NULL)) { - if (deps && wp_spa_json_is_array (deps)) { - component->deps = g_steal_pointer (&deps); + if (wp_spa_json_is_array (deps)) { + comp->deps = g_steal_pointer (&deps); } else { - wp_warning ("deps must be an array for component(%s), skip loading it", - component->name); + wp_warning ("skipping component %s as its 'deps' is not a JSON array", + comp->name); + component_data_free (comp); continue; } } + /* Parse flags (optional) */ if (wp_spa_json_object_get (cjson, "flags", "J", &flags, NULL)) { if (flags && wp_spa_json_is_array (flags)) { g_autoptr (WpIterator) it = wp_spa_json_new_iterator (flags); @@ -382,124 +302,34 @@ do_parse_json_components (void *data, const char *location, const char *section, g_autofree gchar *flag_str = wp_spa_json_parse_string (flag); if (g_str_equal (flag_str, "ifexists")) - component->flags |= IF_EXISTS; + comp->flags |= IF_EXISTS; else if (g_str_equal (flag_str, "nofail")) - component->flags |= NO_FAIL; + comp->flags |= NO_FAIL; else - wp_warning ("flag(%s) is not valid for component(%s)", flag_str, - component->name); + wp_warning ("flag '%s' is not valid for component '%s'", flag_str, + comp->name); } } else { - wp_warning ("flags must be an array for component(%s), skip loading it", - component->name); + wp_warning ("skipping component %s as its 'flags' is not a JSON array", + comp->name); + component_data_free (comp); continue; } } - if (!g_list_find_custom (d->components, component->name, - (GCompareFunc) is_component_present)) { - wp_trace (".. parsed component(%s) type(%s) priority(%d) flags(%x) " - "deps defined(%s)", component->name, component->type, - component->priority, component->flags, - (component->deps) ? "true" : "false"); - - d->components = g_list_insert_sorted (d->components, - g_steal_pointer (&component), (GCompareFunc) component_cmp_func); - } else - wp_info (".. component(%s) already present, ignore this entry", - component->name); - - d->count++; + /* Insert component into the list if it does not exist */ + if (!g_list_find_custom (*list, comp, + (GCompareFunc) component_equal_func)) { + wp_trace ("appended component '%s' of type '%s' with priority '%d'", + comp->name, comp->type, comp->priority); + *list = g_list_insert_sorted (*list, g_steal_pointer (&comp), + (GCompareFunc) component_cmp_func); + } else { + wp_debug ("ignoring component '%s' as it is already defined previously", + comp->name); + component_data_free (comp); + } } - return 0; -} - -static gboolean -do_parse_dangling_component (const GValue *item, GValue *ret, gpointer data) -{ - GList *comps = data; - const gchar *path = g_value_dup_string (item); - g_autofree gchar *basename = NULL; - g_autoptr (component_data) comp = g_slice_new0 (component_data); - - comp->type = pick_component_type (path); - comp->name = (gchar *) path; - comp->priority = pick_default_component_priority (path); - - if (!(basename = extract_base_name (path))) { - wp_warning (".. ignore dangling shared object(%s), it is not a wireplumber" - " module", path); - return TRUE; - } - - if (!g_list_find_custom (comps, basename, - (GCompareFunc) is_component_present)) { - wp_debug (".. parsed dangling component(%s) type(%s)", comp->name, - comp->type); - comps = g_list_insert_sorted (comps, g_steal_pointer (&comp), - (GCompareFunc) component_cmp_func); - } else - wp_warning (".. dangling component(%s) already present, ignore this one", - comp->name); - - g_value_set_int (ret, g_value_get_int (ret) + 1); - return TRUE; -} - -#define CONFIG_DIRS_LOOKUP_SET \ - (WP_LOOKUP_DIR_ENV_CONFIG | \ - WP_LOOKUP_DIR_XDG_CONFIG_HOME | \ - WP_LOOKUP_DIR_ETC | \ - WP_LOOKUP_DIR_PREFIX_SHARE) - -/* - * dangling components are those not present in the json config files but - * present in the wireplumber lookup folders. - */ -static gboolean -do_parse_dangling_components (GList *components, GError **error) -{ - g_autoptr (WpIterator) it = NULL; - g_auto (GValue) fold_ret = G_VALUE_INIT; - gint nfiles = 0; - - /* look for 'modules' folder in the look up folders*/ - it = wp_new_files_iterator (CONFIG_DIRS_LOOKUP_SET, "modules", ".so"); - - g_value_init (&fold_ret, G_TYPE_INT); - g_value_set_int (&fold_ret, nfiles); - if (!wp_iterator_fold (it, do_parse_dangling_component, &fold_ret, - components)) { - if (error && G_VALUE_HOLDS (&fold_ret, G_TYPE_ERROR)) - *error = g_value_dup_boxed (&fold_ret); - return FALSE; - } - nfiles = g_value_get_int (&fold_ret); - if (nfiles > 0) { - wp_info (".. parsed %d dangling modules", nfiles); - } - - g_clear_pointer (&it, wp_iterator_unref); - g_value_unset (&fold_ret); - nfiles = 0; - - /* look for 'scripts' folder in the look up folders*/ - it = wp_new_files_iterator (CONFIG_DIRS_LOOKUP_SET, "scripts", ".lua"); - - g_value_init (&fold_ret, G_TYPE_INT); - g_value_set_int (&fold_ret, nfiles); - if (!wp_iterator_fold (it, do_parse_dangling_component, &fold_ret, - components)) { - if (error && G_VALUE_HOLDS (&fold_ret, G_TYPE_ERROR)) - *error = g_value_dup_boxed (&fold_ret); - return FALSE; - } - nfiles = g_value_get_int (&fold_ret); - if (nfiles > 0) { - wp_info (".. parsed %d dangling scripts", nfiles); - } - - return TRUE; } static void @@ -552,47 +382,25 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) } case STEP_PARSE_COMPONENTS: { - struct data data = { .transition = transition, .components = NULL }; - GError *error = NULL; - wp_info_object (self, "parse wireplumber components..."); + g_autoptr (WpConf) conf = wp_conf_get_instance (core); + g_autoptr (WpSpaJson) json_comps = NULL; - if (pw_context_conf_section_for_each (pw_ctx, "wireplumber.components", - do_parse_json_components, &data) < 0) - return; + wp_info_object (self, "parsing components..."); - if (data.count == 0) { - wp_transition_return_error (transition, g_error_new ( - WP_DOMAIN_DAEMON, WP_EXIT_CONFIG, - "No components configured in the context conf file; nothing to do")); - return; - } + /* Append components that are defined in the configuration section */ + json_comps = wp_conf_get_section (conf, "wireplumber.components", NULL); + if (json_comps) + append_json_components (&self->components, json_comps); - if (!do_parse_dangling_components (data.components, &error)) { - wp_warning ("..error in traversing dangling components (%s)", - error->message); - wp_transition_return_error (transition, error); - } - - self->components = g_steal_pointer (&data.components); wp_transition_advance (transition); break; } - case STEP_LOAD_ENABLE_COMPONENTS: { - g_autoptr (GError) error = NULL; - int ret = 0; - wp_info ("load enable components.."); - - ret = load_enable_component (self, &error); - if (ret < 0) { - wp_transition_return_error (transition, g_steal_pointer (&error)); - } else if (ret == 0) { - g_set_error (&error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED, - "list of components not available to load"); - wp_transition_return_error (transition, g_steal_pointer (&error)); - } + case STEP_LOAD_ENABLE_COMPONENTS: + wp_info ("loading and enabling components..."); + if (load_enable_components (self)) + wp_transition_advance (WP_TRANSITION (self)); break; - } case STEP_CHECK_MEDIA_SESSION: { wp_info_object (self, "Checking for session manager conflicts..."); @@ -610,12 +418,14 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) case STEP_CLEANUP: wp_info ("wirePlumber initialized"); g_clear_object (&self->om); - g_list_free_full (self->components, (GDestroyNotify) component_unref); + g_list_free_full (self->components, (GDestroyNotify) component_data_free); + self->components = NULL; break; case WP_TRANSITION_STEP_ERROR: g_clear_object (&self->om); - g_list_free_full (self->components, (GDestroyNotify) component_unref); + g_list_free_full (self->components, (GDestroyNotify) component_data_free); + self->components = NULL; break; default: diff --git a/src/tools/wpctl.c b/src/tools/wpctl.c index b64874ec..ea8ebf5f 100644 --- a/src/tools/wpctl.c +++ b/src/tools/wpctl.c @@ -25,7 +25,6 @@ struct _WpCtl GOptionContext *context; GMainLoop *loop; WpCore *core; - GPtrArray *apis; WpObjectManager *om; guint pending_plugins; gint exit_code; @@ -75,7 +74,6 @@ G_DEFINE_QUARK (wpctl-error, wpctl_error_domain) static void wp_ctl_clear (WpCtl * self) { - g_clear_pointer (&self->apis, g_ptr_array_unref); g_clear_object (&self->om); g_clear_object (&self->core); g_clear_pointer (&self->loop, g_main_loop_unref); @@ -1305,17 +1303,25 @@ static const struct subcommand { }; static void -on_plugin_activated (WpObject * p, GAsyncResult * res, WpCtl * ctl) +on_plugin_loaded (WpCore * core, GAsyncResult * res, WpCtl *ctl) { - g_autoptr (GError) error = NULL; + g_autoptr (GObject) o = NULL; + GError *error = NULL; - if (!wp_object_activate_finish (p, res, &error)) { - fprintf (stderr, "%s", error->message); + o = wp_core_load_component_finish (core, res, &error); + if (!o) { + fprintf (stderr, "%s\n", error->message); ctl->exit_code = 1; g_main_loop_quit (ctl->loop); return; } + if (WP_IS_PLUGIN (o)) { + const gchar *name = wp_plugin_get_name (WP_PLUGIN (o)); + if (g_str_equal (name, "mixer-api")) + g_object_set (o, "scale", 1 /* cubic */, NULL); + } + if (--ctl->pending_plugins == 0) wp_core_install_object_manager (ctl->core, ctl->om); } @@ -1336,7 +1342,6 @@ main (gint argc, gchar **argv) "COMMAND [COMMAND_OPTIONS] - WirePlumber Control CLI"); ctl.loop = g_main_loop_new (NULL, FALSE); ctl.core = wp_core_new (NULL, NULL); - ctl.apis = g_ptr_array_new_with_free_func (g_object_unref); ctl.om = wp_object_manager_new (); /* find the subcommand */ @@ -1403,22 +1408,12 @@ main (gint argc, gchar **argv) } /* load required API modules */ - if (!wp_core_load_component (ctl.core, - "libwireplumber-module-default-nodes-api", "module", NULL, &error)) { - fprintf (stderr, "%s\n", error->message); - return 1; - } - if (!wp_core_load_component (ctl.core, - "libwireplumber-module-mixer-api", "module", NULL, &error)) { - fprintf (stderr, "%s\n", error->message); - return 1; - } - g_ptr_array_add (ctl.apis, wp_plugin_find (ctl.core, "default-nodes-api")); - g_ptr_array_add (ctl.apis, ({ - WpPlugin *p = wp_plugin_find (ctl.core, "mixer-api"); - g_object_set (G_OBJECT (p), "scale", 1 /* cubic */, NULL); - p; - })); + ctl.pending_plugins++; + wp_core_load_component (ctl.core, "libwireplumber-module-default-nodes-api", + "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl); + ctl.pending_plugins++; + wp_core_load_component (ctl.core, "libwireplumber-module-mixer-api", + "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl); /* connect */ if (!wp_core_connect (ctl.core)) { @@ -1432,13 +1427,6 @@ main (gint argc, gchar **argv) g_signal_connect_swapped (ctl.om, "installed", (GCallback) cmd->run, &ctl); - for (guint i = 0; i < ctl.apis->len; i++) { - WpPlugin *plugin = g_ptr_array_index (ctl.apis, i); - ctl.pending_plugins++; - wp_object_activate (WP_OBJECT (plugin), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, &ctl); - } - g_main_loop_run (ctl.loop); wp_ctl_clear (&ctl); diff --git a/src/tools/wpexec.c b/src/tools/wpexec.c index f207668c..077e3e30 100644 --- a/src/tools/wpexec.c +++ b/src/tools/wpexec.c @@ -103,10 +103,13 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step) } static void -on_plugin_activated (WpObject * p, GAsyncResult * res, WpInitTransition *self) +on_plugin_loaded (WpCore * core, GAsyncResult * res, WpInitTransition *self) { + g_autoptr (GObject) o = NULL; GError *error = NULL; - if (!wp_object_activate_finish (p, res, &error)) { + + o = wp_core_load_component_finish (core, res, &error); + if (!o) { wp_transition_return_error (WP_TRANSITION (self), error); return; } @@ -119,7 +122,6 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) { WpInitTransition *self = WP_INIT_TRANSITION (transition); WpCore *core = wp_transition_get_source_object (transition); - GError *error = NULL; switch (step) { case STEP_CONNECT: @@ -134,42 +136,17 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) break; case STEP_ACTIVATE_PLUGINS: { - if (!wp_core_load_component (core, "libwireplumber-module-lua-scripting", - "module", NULL, &error)) { - wp_transition_return_error (transition, error); - return; - } - if (!wp_core_load_component (core, - "libwireplumber-module-standard-event-source", "module", NULL, - &error)) { - wp_transition_return_error (transition, error); - return; - } - g_autoptr (WpPlugin) p = wp_plugin_find (core, "lua-scripting"); - wp_object_activate (WP_OBJECT (p), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, self); - - g_clear_object (&p); - p = wp_plugin_find (core, "standard-event-source"); - wp_object_activate (WP_OBJECT (p), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, self); + wp_core_load_component (core, "libwireplumber-module-lua-scripting", + "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, self); + wp_core_load_component (core, "libwireplumber-module-standard-event-source", + "module", NULL, (GAsyncReadyCallback) on_plugin_loaded, self); break; } case STEP_ACTIVATE_SCRIPT: { - GVariant *args = g_variant_builder_end (&exec_args_b); - if (!wp_core_load_component (core, exec_script, "script/lua", args, - &error)) { - wp_transition_return_error (transition, error); - return; - } - - g_autofree gchar *name = g_strdup_printf ("script:%s", exec_script); - g_autoptr (WpPlugin) p = wp_plugin_find (core, name); - - wp_object_activate (WP_OBJECT (p), WP_PLUGIN_FEATURE_ENABLED, NULL, - (GAsyncReadyCallback) on_plugin_activated, self); + wp_core_load_component (core, exec_script, "script/lua", args, + (GAsyncReadyCallback) on_plugin_loaded, self); break; } diff --git a/tests/modules/file-monitor.c b/tests/modules/file-monitor.c index 807ddcbd..68105b29 100644 --- a/tests/modules/file-monitor.c +++ b/tests/modules/file-monitor.c @@ -19,15 +19,28 @@ typedef struct { gchar *evtype; } TestFixture; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); + + g_main_loop_quit (f->base.loop); +} + static void test_file_monitor_setup (TestFixture * f, gconstpointer user_data) { wp_base_test_fixture_setup (&f->base, WP_BASE_TEST_FLAG_DONT_CONNECT); - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-file-monitor-api", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-file-monitor-api", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); + g_main_loop_run (f->base.loop); f->plugin = wp_plugin_find (f->base.core, "file-monitor-api"); g_assert_nonnull (f->plugin); @@ -46,16 +59,6 @@ test_file_monitor_teardown (TestFixture * f, gconstpointer user_data) wp_base_test_fixture_teardown (&f->base); } -static void -on_plugin_activated (WpObject * plugin, GAsyncResult * res, TestFixture * f) -{ - g_autoptr (GError) error = NULL; - if (!wp_object_activate_finish (plugin, res, &error)) { - wp_critical_object (plugin, "%s", error->message); - g_main_loop_quit (f->base.loop); - } -} - static void on_changed (WpPlugin *plugin, const gchar *file, const gchar *old, const char *evtype, TestFixture * f) @@ -72,11 +75,6 @@ test_file_monitor_basic (TestFixture * f, gconstpointer user_data) { gboolean res = FALSE; - /* activate plugin */ - g_assert_nonnull (f->plugin); - wp_object_activate (WP_OBJECT (f->plugin), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - /* delete the 'foo' file if it exists in path */ g_autofree gchar *filename = g_build_filename (f->path, "foo", NULL); (void) remove (filename); diff --git a/tests/modules/reserve-device.c b/tests/modules/reserve-device.c index 75de4884..67f9e9b6 100644 --- a/tests/modules/reserve-device.c +++ b/tests/modules/reserve-device.c @@ -21,6 +21,19 @@ typedef struct { gint expected_rd2_state; } RdTestFixture; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, RdTestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); + + g_main_loop_quit (f->base.loop); +} + static void test_rd_setup (RdTestFixture *f, gconstpointer data) { @@ -31,16 +44,16 @@ test_rd_setup (RdTestFixture *f, gconstpointer data) g_test_dbus_up (f->test_dbus); { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-reserve-device", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-reserve-device", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); + g_main_loop_run (f->base.loop); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.client_core, - "libwireplumber-module-reserve-device", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-reserve-device", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); + g_main_loop_run (f->base.loop); } f->rd_plugin_1 = wp_plugin_find (f->base.core, "reserve-device"); @@ -68,16 +81,6 @@ test_rd_teardown (RdTestFixture *f, gconstpointer data) wp_base_test_fixture_teardown (&f->base); } -static void -on_plugin_activated (WpObject * plugin, GAsyncResult * res, RdTestFixture * f) -{ - g_autoptr (GError) error = NULL; - if (!wp_object_activate_finish (plugin, res, &error)) { - wp_critical_object (plugin, "%s", error->message); - g_main_loop_quit (f->base.loop); - } -} - static void ensure_plugins_stable_state (GObject * obj, GParamSpec * spec, RdTestFixture *f) { @@ -92,24 +95,13 @@ static void test_rd_plugin (RdTestFixture *f, gconstpointer data) { GObject *rd1 = NULL, *rd2 = NULL, *rd_video = NULL, *tmp = NULL; - gint state = 0xffff; + gint state = 0; gchar *str; - g_object_get (f->dbus_1, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - g_object_get (f->dbus_2, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - - wp_object_activate (WP_OBJECT (f->rd_plugin_1), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - wp_object_activate (WP_OBJECT (f->rd_plugin_2), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - g_signal_connect (f->dbus_1, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); g_signal_connect (f->dbus_2, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); - g_main_loop_run (f->base.loop); g_object_get (f->dbus_1, "state", &state, NULL); g_assert_cmpint (state, ==, 2); @@ -183,23 +175,12 @@ static void test_rd_conn_closed (RdTestFixture *f, gconstpointer data) { GObject *rd1 = NULL; - gint state = 0xffff; - - g_object_get (f->dbus_1, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - g_object_get (f->dbus_2, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - - wp_object_activate (WP_OBJECT (f->rd_plugin_1), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - wp_object_activate (WP_OBJECT (f->rd_plugin_2), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); + gint state = 0; g_signal_connect (f->dbus_1, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); g_signal_connect (f->dbus_2, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); - g_main_loop_run (f->base.loop); g_object_get (f->dbus_1, "state", &state, NULL); g_assert_cmpint (state, ==, 2); @@ -260,24 +241,13 @@ static void test_rd_acquire_release (RdTestFixture *f, gconstpointer data) { GObject *rd1 = NULL, *rd2 = NULL; - gint state = 0xffff; + gint state = 0; gchar *str = NULL; - g_object_get (f->dbus_1, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - g_object_get (f->dbus_2, "state", &state, NULL); - g_assert_cmpint (state, ==, 0); - - wp_object_activate (WP_OBJECT (f->rd_plugin_1), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - wp_object_activate (WP_OBJECT (f->rd_plugin_2), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) on_plugin_activated, f); - g_signal_connect (f->dbus_1, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); g_signal_connect (f->dbus_2, "notify::state", G_CALLBACK (ensure_plugins_stable_state), f); - g_main_loop_run (f->base.loop); g_object_get (f->dbus_1, "state", &state, NULL); g_assert_cmpint (state, ==, 2); diff --git a/tests/modules/si-audio-adapter.c b/tests/modules/si-audio-adapter.c index 7398f9de..8a6f648b 100644 --- a/tests/modules/si-audio-adapter.c +++ b/tests/modules/si-audio-adapter.c @@ -12,6 +12,17 @@ typedef struct { WpBaseTestFixture base; } TestFixture; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); +} + static void test_si_audio_adapter_setup (TestFixture * f, gconstpointer user_data) { @@ -30,10 +41,9 @@ test_si_audio_adapter_setup (TestFixture * f, gconstpointer user_data) "libpipewire-module-adapter", NULL, NULL)); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-audio-adapter", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-audio-adapter", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } } diff --git a/tests/modules/si-audio-virtual.c b/tests/modules/si-audio-virtual.c index ff139872..dc2c5463 100644 --- a/tests/modules/si-audio-virtual.c +++ b/tests/modules/si-audio-virtual.c @@ -12,6 +12,17 @@ typedef struct { WpBaseTestFixture base; } TestFixture; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); +} + static void test_si_audio_virtual_setup (TestFixture * f, gconstpointer user_data) { @@ -28,16 +39,14 @@ test_si_audio_virtual_setup (TestFixture * f, gconstpointer user_data) "libpipewire-module-adapter", NULL, NULL)); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-audio-adapter", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-audio-adapter", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-audio-virtual", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-audio-virtual", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } } diff --git a/tests/modules/si-node.c b/tests/modules/si-node.c index a116a64a..68256c18 100644 --- a/tests/modules/si-node.c +++ b/tests/modules/si-node.c @@ -20,6 +20,17 @@ typedef struct { WpDirection expected_direction; } TestData; +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); +} + static void test_si_node_setup (TestFixture * f, gconstpointer user_data) { @@ -36,10 +47,9 @@ test_si_node_setup (TestFixture * f, gconstpointer user_data) "libpipewire-module-spa-node-factory", NULL, NULL)); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-node", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-node", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } } diff --git a/tests/modules/si-standard-link.c b/tests/modules/si-standard-link.c index 7845b127..a400c4da 100644 --- a/tests/modules/si-standard-link.c +++ b/tests/modules/si-standard-link.c @@ -65,6 +65,17 @@ load_node (TestFixture * f, const gchar * factory, const gchar * media_class, return g_steal_pointer (&adapter); } +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, TestFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); +} + static void test_si_standard_link_setup (TestFixture * f, gconstpointer user_data) { @@ -83,14 +94,13 @@ test_si_standard_link_setup (TestFixture * f, gconstpointer user_data) "libpipewire-module-link-factory", NULL, NULL)); } { - g_autoptr (GError) error = NULL; wp_core_load_component (f->base.core, - "libwireplumber-module-si-audio-adapter", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-audio-adapter", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); wp_core_load_component (f->base.core, - "libwireplumber-module-si-standard-link", "module", NULL, &error); - g_assert_no_error (error); + "libwireplumber-module-si-standard-link", "module", NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); } if (test_is_spa_lib_installed (&f->base, "audiotestsrc")) diff --git a/tests/script-tester.c b/tests/script-tester.c index cf1cd643..66abbdb4 100644 --- a/tests/script-tester.c +++ b/tests/script-tester.c @@ -169,6 +169,20 @@ wp_script_tester_class_init (WpScriptTesterClass *klass) } +static void +on_plugin_loaded (WpCore * core, GAsyncResult * res, ScriptRunnerFixture *f) +{ + g_autoptr (GObject) o = NULL; + GError *error = NULL; + + o = wp_core_load_component_finish (core, res, &error); + g_assert_nonnull (o); + g_assert_no_error (error); + + if (WP_IS_PLUGIN (o)) + g_main_loop_quit (f->base.loop); +} + static void load_component (ScriptRunnerFixture *f, const gchar *name, const gchar *type) { @@ -191,17 +205,11 @@ load_component (ScriptRunnerFixture *f, const gchar *name, const gchar *type) plugin_name = g_strdup (name); } - wp_core_load_component (f->base.core, component_name, type, NULL, &error); - g_assert_no_error (error); - - if (!g_str_has_prefix (name, "si")) { - g_autoptr (WpPlugin) plugin = wp_plugin_find (f->base.core, plugin_name); - - wp_object_activate (WP_OBJECT (plugin), WP_PLUGIN_FEATURE_ENABLED, - NULL, (GAsyncReadyCallback) test_object_activate_finish_cb, f); + wp_core_load_component (f->base.core, component_name, type, NULL, + (GAsyncReadyCallback) on_plugin_loaded, f); + if (!g_str_has_prefix (name, "si")) g_main_loop_run (f->base.loop); - } } static void