core: introduce the notion of provided features on components
Each component can optionally "provide" a feature, which is basically a string that describes the feature (ex. "support.dbus"). If the component loads successfully, the feature is marked as provided and can be tested for its presence with wp_core_test_feature()
This commit is contained in:
@@ -95,6 +95,8 @@ on_component_loader_load_done (WpComponentLoader * cl, GAsyncResult * res,
|
|||||||
g_autoptr (GError) error = NULL;
|
g_autoptr (GError) error = NULL;
|
||||||
g_autoptr (GObject) o = NULL;
|
g_autoptr (GObject) o = NULL;
|
||||||
WpCore *core = g_task_get_source_object (task);
|
WpCore *core = g_task_get_source_object (task);
|
||||||
|
WpRegistry *reg = wp_core_get_registry (core);
|
||||||
|
gchar *provides = g_task_get_task_data (task);
|
||||||
|
|
||||||
o = wp_component_loader_load_finish (cl, res, &error);
|
o = wp_component_loader_load_finish (cl, res, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -102,11 +104,14 @@ on_component_loader_load_done (WpComponentLoader * cl, GAsyncResult * res,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (provides)
|
||||||
|
wp_registry_mark_feature_provided (reg, provides);
|
||||||
|
|
||||||
if (o) {
|
if (o) {
|
||||||
wp_trace_object (cl, "loaded object " WP_OBJECT_FORMAT, WP_OBJECT_ARGS (o));
|
wp_trace_object (cl, "loaded object " WP_OBJECT_FORMAT, WP_OBJECT_ARGS (o));
|
||||||
|
|
||||||
/* store object in the registry */
|
/* store object in the registry */
|
||||||
wp_registry_register_object (wp_core_get_registry (core), g_object_ref (o));
|
wp_registry_register_object (reg, g_object_ref (o));
|
||||||
|
|
||||||
if (WP_IS_OBJECT (o)) {
|
if (WP_IS_OBJECT (o)) {
|
||||||
/* WpObject needs to be activated */
|
/* WpObject needs to be activated */
|
||||||
@@ -132,18 +137,21 @@ on_component_loader_load_done (WpComponentLoader * cl, GAsyncResult * res,
|
|||||||
*
|
*
|
||||||
* \ingroup wpcomponentloader
|
* \ingroup wpcomponentloader
|
||||||
* \param self the core
|
* \param self the core
|
||||||
* \param component the module name or file name
|
* \param component (nullable): the module name or file name
|
||||||
* \param type the type of the component
|
* \param type the type of the component
|
||||||
* \param args (transfer none)(nullable): additional arguments for the component,
|
* \param args (transfer none)(nullable): additional arguments for the component,
|
||||||
* expected to be a JSON object
|
* expected to be a JSON object
|
||||||
|
* \param provides (nullable): the name of the feature that this component will
|
||||||
|
* provide if it loads successfully; this can be queried later with
|
||||||
|
* wp_core_test_feature()
|
||||||
* \param cancellable (nullable): optional GCancellable
|
* \param cancellable (nullable): optional GCancellable
|
||||||
* \param callback (scope async): the callback to call when the operation is done
|
* \param callback (scope async): the callback to call when the operation is done
|
||||||
* \param data (closure): data to pass to \a callback
|
* \param data (closure): data to pass to \a callback
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
wp_core_load_component (WpCore * self, const gchar * component,
|
wp_core_load_component (WpCore * self, const gchar * component,
|
||||||
const gchar * type, WpSpaJson * args, GCancellable * cancellable,
|
const gchar * type, WpSpaJson * args, const gchar * provides,
|
||||||
GAsyncReadyCallback callback, gpointer data)
|
GCancellable * cancellable, GAsyncReadyCallback callback, gpointer data)
|
||||||
{
|
{
|
||||||
g_autoptr (GTask) task = NULL;
|
g_autoptr (GTask) task = NULL;
|
||||||
g_autoptr (WpComponentLoader) cl = NULL;
|
g_autoptr (WpComponentLoader) cl = NULL;
|
||||||
@@ -151,6 +159,9 @@ wp_core_load_component (WpCore * self, const gchar * component,
|
|||||||
task = g_task_new (self, cancellable, callback, data);
|
task = g_task_new (self, cancellable, callback, data);
|
||||||
g_task_set_source_tag (task, wp_core_load_component);
|
g_task_set_source_tag (task, wp_core_load_component);
|
||||||
|
|
||||||
|
if (provides)
|
||||||
|
g_task_set_task_data (task, g_strdup (provides), g_free);
|
||||||
|
|
||||||
/* find a component loader for that type and load the component */
|
/* find a component loader for that type and load the component */
|
||||||
cl = wp_component_loader_find (self, type);
|
cl = wp_component_loader_find (self, type);
|
||||||
if (!cl) {
|
if (!cl) {
|
||||||
|
@@ -42,8 +42,8 @@ struct _WpComponentLoaderInterface
|
|||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
void wp_core_load_component (WpCore * self, const gchar * component,
|
void wp_core_load_component (WpCore * self, const gchar * component,
|
||||||
const gchar * type, WpSpaJson * args, GCancellable * cancellable,
|
const gchar * type, WpSpaJson * args, const gchar * provides,
|
||||||
GAsyncReadyCallback callback, gpointer data);
|
GCancellable * cancellable, GAsyncReadyCallback callback, gpointer data);
|
||||||
|
|
||||||
WP_API
|
WP_API
|
||||||
gboolean wp_core_load_component_finish (WpCore * self, GAsyncResult * res,
|
gboolean wp_core_load_component_finish (WpCore * self, GAsyncResult * res,
|
||||||
|
@@ -1052,6 +1052,21 @@ wp_core_sync_finish (WpCore * self, GAsyncResult * res, GError ** error)
|
|||||||
return g_task_propagate_boolean (G_TASK (res), error);
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Test if a global feature is provided
|
||||||
|
*
|
||||||
|
* \ingroup wpcore
|
||||||
|
* \param self the core
|
||||||
|
* \param feature the feature name
|
||||||
|
* \returns TRUE if the feature is provided, FALSE otherwise
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
wp_core_test_feature (WpCore * self, const gchar * feature)
|
||||||
|
{
|
||||||
|
return g_ptr_array_find_with_equal_func (self->registry.features, feature,
|
||||||
|
g_str_equal, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
WpRegistry *
|
WpRegistry *
|
||||||
wp_core_get_registry (WpCore * self)
|
wp_core_get_registry (WpCore * self)
|
||||||
{
|
{
|
||||||
|
@@ -120,6 +120,11 @@ gboolean wp_core_sync_finish (WpCore * self, GAsyncResult * res,
|
|||||||
WP_API
|
WP_API
|
||||||
void wp_core_install_object_manager (WpCore * self, WpObjectManager * om);
|
void wp_core_install_object_manager (WpCore * self, WpObjectManager * om);
|
||||||
|
|
||||||
|
/* Global Features */
|
||||||
|
|
||||||
|
WP_API
|
||||||
|
gboolean wp_core_test_feature (WpCore * self, const gchar * feature);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -961,6 +961,7 @@ wp_registry_init (WpRegistry *self)
|
|||||||
g_ptr_array_new_with_free_func ((GDestroyNotify) wp_global_unref);
|
g_ptr_array_new_with_free_func ((GDestroyNotify) wp_global_unref);
|
||||||
self->objects = g_ptr_array_new_with_free_func (g_object_unref);
|
self->objects = g_ptr_array_new_with_free_func (g_object_unref);
|
||||||
self->object_managers = g_ptr_array_new ();
|
self->object_managers = g_ptr_array_new ();
|
||||||
|
self->features = g_ptr_array_new_with_free_func (g_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -969,6 +970,7 @@ wp_registry_clear (WpRegistry *self)
|
|||||||
wp_registry_detach (self);
|
wp_registry_detach (self);
|
||||||
g_clear_pointer (&self->globals, g_ptr_array_unref);
|
g_clear_pointer (&self->globals, g_ptr_array_unref);
|
||||||
g_clear_pointer (&self->tmp_globals, g_ptr_array_unref);
|
g_clear_pointer (&self->tmp_globals, g_ptr_array_unref);
|
||||||
|
g_clear_pointer (&self->features, g_ptr_array_unref);
|
||||||
|
|
||||||
/* remove all the registered objects
|
/* remove all the registered objects
|
||||||
this will normally also destroy the object managers, eventually, since
|
this will normally also destroy the object managers, eventually, since
|
||||||
|
@@ -292,7 +292,7 @@ wp_component_array_load_task_execute_step (WpTransition * transition, guint step
|
|||||||
self->curr_component->name, self->curr_component->type,
|
self->curr_component->name, self->curr_component->type,
|
||||||
self->curr_component->priority, self->curr_component->flags);
|
self->curr_component->priority, self->curr_component->flags);
|
||||||
wp_core_load_component (core, self->curr_component->name,
|
wp_core_load_component (core, self->curr_component->name,
|
||||||
self->curr_component->type, NULL, NULL,
|
self->curr_component->type, NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_component_loaded, self);
|
(GAsyncReadyCallback) on_component_loaded, self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@@ -30,6 +30,7 @@ struct _WpRegistry
|
|||||||
GPtrArray *tmp_globals; // elementy-type: WpGlobal*
|
GPtrArray *tmp_globals; // elementy-type: WpGlobal*
|
||||||
GPtrArray *objects; // element-type: GObject*
|
GPtrArray *objects; // element-type: GObject*
|
||||||
GPtrArray *object_managers; // element-type: WpObjectManager*
|
GPtrArray *object_managers; // element-type: WpObjectManager*
|
||||||
|
GPtrArray *features; // element-type: gchar*
|
||||||
};
|
};
|
||||||
|
|
||||||
void wp_registry_init (WpRegistry *self);
|
void wp_registry_init (WpRegistry *self);
|
||||||
@@ -47,6 +48,12 @@ gpointer wp_registry_find_object (WpRegistry *reg, GEqualFunc func,
|
|||||||
void wp_registry_register_object (WpRegistry *reg, gpointer obj);
|
void wp_registry_register_object (WpRegistry *reg, gpointer obj);
|
||||||
void wp_registry_remove_object (WpRegistry *reg, gpointer obj);
|
void wp_registry_remove_object (WpRegistry *reg, gpointer obj);
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
wp_registry_mark_feature_provided (WpRegistry * reg, const gchar * feature)
|
||||||
|
{
|
||||||
|
g_ptr_array_add (reg->features, g_strdup (feature));
|
||||||
|
}
|
||||||
|
|
||||||
WpCore * wp_registry_get_core (WpRegistry * self) G_GNUC_CONST;
|
WpCore * wp_registry_get_core (WpRegistry * self) G_GNUC_CONST;
|
||||||
|
|
||||||
/* core */
|
/* core */
|
||||||
|
@@ -92,7 +92,7 @@ wp_require_api_transition_execute_step (WpTransition * transition, guint step)
|
|||||||
"libwireplumber-module-%s", api_name);
|
"libwireplumber-module-%s", api_name);
|
||||||
|
|
||||||
self->pending_plugins++;
|
self->pending_plugins++;
|
||||||
wp_core_load_component (core, module_name, "module", NULL, NULL,
|
wp_core_load_component (core, module_name, "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, self);
|
(GAsyncReadyCallback) on_plugin_loaded, self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -190,7 +190,7 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
|
|||||||
|
|
||||||
/* Load components that are defined in the configuration section */
|
/* Load components that are defined in the configuration section */
|
||||||
json_comps = wp_conf_get_section (conf, "wireplumber.components", NULL);
|
json_comps = wp_conf_get_section (conf, "wireplumber.components", NULL);
|
||||||
wp_core_load_component (core, NULL, "array", json_comps, NULL,
|
wp_core_load_component (core, NULL, "array", json_comps, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_components_loaded, self);
|
(GAsyncReadyCallback) on_components_loaded, self);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -1407,10 +1407,10 @@ main (gint argc, gchar **argv)
|
|||||||
/* load required API modules */
|
/* load required API modules */
|
||||||
ctl.pending_plugins++;
|
ctl.pending_plugins++;
|
||||||
wp_core_load_component (ctl.core, "libwireplumber-module-default-nodes-api",
|
wp_core_load_component (ctl.core, "libwireplumber-module-default-nodes-api",
|
||||||
"module", NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl);
|
"module", NULL, NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl);
|
||||||
ctl.pending_plugins++;
|
ctl.pending_plugins++;
|
||||||
wp_core_load_component (ctl.core, "libwireplumber-module-mixer-api",
|
wp_core_load_component (ctl.core, "libwireplumber-module-mixer-api",
|
||||||
"module", NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl);
|
"module", NULL, NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, &ctl);
|
||||||
|
|
||||||
/* connect */
|
/* connect */
|
||||||
if (!wp_core_connect (ctl.core)) {
|
if (!wp_core_connect (ctl.core)) {
|
||||||
|
@@ -138,14 +138,14 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
|
|||||||
|
|
||||||
case STEP_ACTIVATE_PLUGINS: {
|
case STEP_ACTIVATE_PLUGINS: {
|
||||||
wp_core_load_component (core, "libwireplumber-module-lua-scripting",
|
wp_core_load_component (core, "libwireplumber-module-lua-scripting",
|
||||||
"module", NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, self);
|
"module", NULL, NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, self);
|
||||||
wp_core_load_component (core, "libwireplumber-module-standard-event-source",
|
wp_core_load_component (core, "libwireplumber-module-standard-event-source",
|
||||||
"module", NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, self);
|
"module", NULL, NULL, NULL, (GAsyncReadyCallback) on_plugin_loaded, self);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case STEP_ACTIVATE_SCRIPT: {
|
case STEP_ACTIVATE_SCRIPT: {
|
||||||
wp_core_load_component (core, exec_script, "script/lua", exec_args, NULL,
|
wp_core_load_component (core, exec_script, "script/lua", exec_args, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, self);
|
(GAsyncReadyCallback) on_plugin_loaded, self);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -62,7 +62,7 @@ test_dbus_connection (TestFixture *f, gconstpointer user_data)
|
|||||||
WpDBusConnectionState state = -1;
|
WpDBusConnectionState state = -1;
|
||||||
|
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-dbus-connection", "module", NULL, NULL,
|
"libwireplumber-module-dbus-connection", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
|
|
||||||
|
@@ -38,7 +38,7 @@ test_file_monitor_setup (TestFixture * f, gconstpointer user_data)
|
|||||||
wp_base_test_fixture_setup (&f->base, WP_BASE_TEST_FLAG_DONT_CONNECT);
|
wp_base_test_fixture_setup (&f->base, WP_BASE_TEST_FLAG_DONT_CONNECT);
|
||||||
|
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-file-monitor-api", "module", NULL, NULL,
|
"libwireplumber-module-file-monitor-api", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
|
|
||||||
|
@@ -47,25 +47,25 @@ test_rd_setup (RdTestFixture *f, gconstpointer data)
|
|||||||
|
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-dbus-connection", "module", NULL, NULL,
|
"libwireplumber-module-dbus-connection", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.client_core,
|
wp_core_load_component (f->base.client_core,
|
||||||
"libwireplumber-module-dbus-connection", "module", NULL, NULL,
|
"libwireplumber-module-dbus-connection", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-reserve-device", "module", NULL, NULL,
|
"libwireplumber-module-reserve-device", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.client_core,
|
wp_core_load_component (f->base.client_core,
|
||||||
"libwireplumber-module-reserve-device", "module", NULL, NULL,
|
"libwireplumber-module-reserve-device", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,7 @@ test_si_audio_adapter_setup (TestFixture * f, gconstpointer user_data)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL,
|
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
|
@@ -42,13 +42,13 @@ test_si_audio_virtual_setup (TestFixture * f, gconstpointer user_data)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL,
|
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-si-audio-virtual", "module", NULL, NULL,
|
"libwireplumber-module-si-audio-virtual", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
|
@@ -50,7 +50,7 @@ test_si_node_setup (TestFixture * f, gconstpointer user_data)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-si-node", "module", NULL, NULL,
|
"libwireplumber-module-si-node", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
|
@@ -97,12 +97,12 @@ test_si_standard_link_setup (TestFixture * f, gconstpointer user_data)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL,
|
"libwireplumber-module-si-audio-adapter", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
|
|
||||||
wp_core_load_component (f->base.core,
|
wp_core_load_component (f->base.core,
|
||||||
"libwireplumber-module-si-standard-link", "module", NULL, NULL,
|
"libwireplumber-module-si-standard-link", "module", NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
|
@@ -204,7 +204,7 @@ load_component (ScriptRunnerFixture *f, const gchar *name, const gchar *type)
|
|||||||
plugin_name = g_strdup (name);
|
plugin_name = g_strdup (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_core_load_component (f->base.core, component_name, type, NULL, NULL,
|
wp_core_load_component (f->base.core, component_name, type, NULL, NULL, NULL,
|
||||||
(GAsyncReadyCallback) on_plugin_loaded, f);
|
(GAsyncReadyCallback) on_plugin_loaded, f);
|
||||||
g_main_loop_run (f->base.loop);
|
g_main_loop_run (f->base.loop);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user