--- a/ChangeLog Sat Apr 11 10:52:48 2020 +0000
+++ b/ChangeLog Fri Apr 10 03:05:31 2020 -0500
@@ -9,6 +9,14 @@
* Removed GPluginVersionCompareFunc and the GPluginPluginInfo::version-func
property as they aren't necessary with semantic versioning. (Gary Kramlich)
* Fixed licenses throughout the codecase. (Richard Laager)
+ * Added new plugin state UNLOAD_FAILED. When a plugin fails to unload, it + now goes to UNLOAD_FAILED instead of LOADED. (Gary Kramlich) + * Added gplugin_manager_foreach and GPluginManagerForeachFunc to make it + easier to operate on all plugins. (Gary Kramlich) + * Added GPluginManager::unload-plugin-failed signal that gets emitted when + a plugin fails to unload. + * Made the GPluginManager::load-failed signal pass in the error, if any, + that the plugin returned. (Gary Kramlich) * Removed the moonscript support from the Lua loader. (Gary Kramlich)
--- a/gplugin/gplugin-loader-tests.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-loader-tests.c Fri Apr 10 03:05:31 2020 -0500
@@ -179,7 +179,7 @@
gplugin_plugin_get_state(plugin),
- GPLUGIN_PLUGIN_STATE_LOADED);
+ GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED); g_object_unref(G_OBJECT(plugin));
--- a/gplugin/gplugin-manager.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-manager.c Fri Apr 10 03:05:31 2020 -0500
@@ -36,6 +36,15 @@
* loading, unloading, querying, checking for new plugins, and so on.
+ * GPluginManagerForeachFunc: + * @id: The id of the plugin. + * @plugins: A #GSList of each plugin that has the id @id. + * @data: User data passed to gplugin_manager_foreach(). + * A callback function for gplugin_manager_foreach(). /******************************************************************************
*****************************************************************************/
@@ -45,6 +54,7 @@
@@ -83,7 +93,15 @@
void (*refresh)(GPluginManager *manager);
+ GPluginManager *manager, + GPluginManagerForeachFunc func, GSList *(*find_plugins)(GPluginManager *manager, const gchar *id);
+ GSList *(*find_plugins_with_state)( + GPluginManager *manager, + GPluginPluginState state); GList *(*list_plugins)(GPluginManager *manager);
@@ -107,13 +125,16 @@
void (*loaded_plugin)(GObject *manager, GPluginPlugin *plugin);
- void (*load_failed)(GObject *manager, GPluginPlugin *plugin);
+ void (*load_failed)(GObject *manager, GPluginPlugin *plugin, GError *error); gboolean (*unloading_plugin)(
void (*unloaded_plugin)(GObject *manager, GPluginPlugin *plugin);
+ void (*unload_plugin_failed)( #define GPLUGIN_TYPE_MANAGER (gplugin_manager_get_type())
@@ -683,6 +704,21 @@
gplugin_file_tree_free(root);
+gplugin_manager_real_foreach( + GPluginManager *manager, + GPluginManagerForeachFunc func, + gpointer id = NULL, plugins = NULL; + g_hash_table_iter_init(&iter, manager->plugins); + while(g_hash_table_iter_next(&iter, &id, &plugins)) { + func((gchar *)id, (GSList *)plugins, data); gplugin_manager_real_find_plugins(GPluginManager *manager, const gchar *id)
@@ -696,6 +732,32 @@
+gplugin_manager_real_find_plugins_with_state( + GPluginManager *manager, + GPluginPluginState state) + GSList *plugins = NULL; + g_hash_table_iter_init(&iter, manager->plugins); + while(g_hash_table_iter_next(&iter, NULL, &value)) { + for(l = (GSList *)value; l != NULL; l = l->next) { + GPluginPlugin *plugin = GPLUGIN_PLUGIN(l->data); + if(gplugin_plugin_get_state(plugin) == state) { + g_slist_prepend(plugins, g_object_ref(G_OBJECT(plugin))); gplugin_manager_real_list_plugins(GPluginManager *manager)
@@ -904,14 +966,20 @@
ret = gplugin_loader_load_plugin(loader, plugin, error);
- gplugin_plugin_set_state(
- (ret) ? GPLUGIN_PLUGIN_STATE_LOADED : GPLUGIN_PLUGIN_STATE_LOAD_FAILED);
+ gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_LOADED); + g_signal_emit(manager, signals[SIG_LOADED], 0, plugin); + GError *real_error = NULL;
- g_signal_emit(manager, signals[SIG_LOADED], 0, plugin);
- g_signal_emit(manager, signals[SIG_LOAD_FAILED], 0, plugin);
+ gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_LOAD_FAILED); + g_signal_emit(manager, signals[SIG_LOAD_FAILED], 0, plugin, real_error); @@ -949,7 +1017,11 @@
gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_QUERIED);
- g_signal_emit(manager, signals[SIG_UNLOADED], 0, plugin, error);
+ g_signal_emit(manager, signals[SIG_UNLOADED], 0, plugin); + gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED); + g_signal_emit(manager, signals[SIG_UNLOAD_FAILED], 0, plugin, error); @@ -1034,7 +1106,11 @@
manager_class->refresh = gplugin_manager_real_refresh;
+ manager_class->foreach = gplugin_manager_real_foreach; manager_class->find_plugins = gplugin_manager_real_find_plugins;
+ manager_class->find_plugins_with_state = + gplugin_manager_real_find_plugins_with_state; manager_class->list_plugins = gplugin_manager_real_list_plugins;
manager_class->get_plugin_dependencies =
@@ -1106,8 +1182,9 @@
* GPluginManager::unloading-plugin:
@@ -1136,7 +1213,7 @@
* @manager: the #gpluginpluginmanager instance. treat as a #gobject.
* @plugin: the #gpluginplugin that's about to be loaded.
- * emitted after a plugin is unloaded.
+ * emitted after a plugin is successfully unloaded. signals[SIG_UNLOADED] = g_signal_new(
@@ -1149,6 +1226,28 @@
+ * GPluginManager::unload-plugin-failed: + * @manager: The #GPluginManager instance. + * @plugin: The #GPluginPlugin instance that failed to unload. + * @error: A #GError instance. + * Emitted when @manager was asked to unload @plugin, but @plugin returned + * %FALSE when it's unload function was called. + signals[SIG_UNLOAD_FAILED] = g_signal_new( + "unload-plugin-failed", + G_OBJECT_CLASS_TYPE(manager_class), + G_STRUCT_OFFSET(GPluginManagerClass, unload_plugin_failed), @@ -1453,6 +1552,27 @@
+ * gplugin_manager_foreach: + * @func: (scope call): The #GPluginManagerForeachFunc to call. + * @data: User data to pass to func. + * Calls @func for each plugin that is known. +gplugin_manager_foreach(GPluginManagerForeachFunc func, gpointer data) + GPluginManager *manager = GPLUGIN_MANAGER_INSTANCE; + GPluginManagerClass *klass = NULL; + g_return_if_fail(GPLUGIN_IS_MANAGER(manager)); + g_return_if_fail(func != NULL); + klass = GPLUGIN_MANAGER_GET_CLASS(manager); + if(klass && klass->foreach) + klass->foreach(manager, func, data); * gplugin_manager_find_plugins:
* @id: id string of the plugin to find.
@@ -1565,6 +1685,32 @@
+ * gplugin_manager_find_plugins_with_state: + * @state: The #GPluginPluginState to look for. + * Finds all plugins that are currently have a state of @state. + * Returns: (element-type GPlugin.Plugin) (transfer full): A #GSList of + * referenced #GPluginPlugin's whose state is @state. Call + * g_slist_free_full() with a `DestroyNotify` of g_object_unref() on + * the returned value when you're done with it. +gplugin_manager_find_plugins_with_state(GPluginPluginState state) + GPluginManager *manager = GPLUGIN_MANAGER_INSTANCE; + GPluginManagerClass *klass = NULL; + g_return_val_if_fail(GPLUGIN_IS_MANAGER(manager), NULL); + klass = GPLUGIN_MANAGER_GET_CLASS(manager); + if(klass && klass->find_plugins_with_state) + return klass->find_plugins_with_state(manager, state); * gplugin_manager_find_plugin:
* @id: The id of the plugin to find.
--- a/gplugin/gplugin-manager.h Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-manager.h Fri Apr 10 03:05:31 2020 -0500
@@ -29,6 +29,11 @@
+typedef void (*GPluginManagerForeachFunc)( void gplugin_manager_append_path(const gchar *path);
void gplugin_manager_prepend_path(const gchar *path);
void gplugin_manager_remove_path(const gchar *path);
@@ -44,11 +49,14 @@
void gplugin_manager_refresh(void);
+void gplugin_manager_foreach(GPluginManagerForeachFunc func, gpointer data); GSList *gplugin_manager_find_plugins(const gchar *id);
GSList *gplugin_manager_find_plugins_with_version(
+GSList *gplugin_manager_find_plugins_with_state(GPluginPluginState state); GPluginPlugin *gplugin_manager_find_plugin(const gchar *id);
--- a/gplugin/gplugin-plugin.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-plugin.c Fri Apr 10 03:05:31 2020 -0500
@@ -38,6 +38,7 @@
* @GPLUGIN_PLUGIN_STATE_REQUERY: The plugin should be requeried.
* @GPLUGIN_PLUGIN_STATE_LOADED: The plugin is loaded.
* @GPLUGIN_PLUGIN_STATE_LOAD_FAILED: The plugin failed to load.
+ * @GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED: The plugin failed to unload. * The known states of a plugin.
--- a/gplugin/gplugin-plugin.h Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-plugin.h Fri Apr 10 03:05:31 2020 -0500
@@ -33,6 +33,7 @@
GPLUGIN_PLUGIN_STATE_REQUERY,
GPLUGIN_PLUGIN_STATE_LOADED,
GPLUGIN_PLUGIN_STATE_LOAD_FAILED,
+ GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED, GPLUGIN_PLUGIN_STATES, /*< skip >*/
--- a/gplugin/tests/meson.build Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/tests/meson.build Fri Apr 10 03:05:31 2020 -0500
@@ -28,6 +28,11 @@
dependencies : [gplugin_dep, GLIB, GOBJECT])
+e = executable('test-find-plugins', 'test-find-plugins.c', + c_args : ['-DTEST_DIR="@0@/plugins/"'.format(meson.current_build_dir())], + dependencies : [gplugin_dep, GLIB, GOBJECT]) e = executable('test-loader-registration', 'test-loader-registration.c',
dependencies : [gplugin_dep, GLIB, GOBJECT])
test('Loader Registration', e)
--- a/gplugin/tests/test-core.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/tests/test-core.c Fri Apr 10 03:05:31 2020 -0500
@@ -1,5 +1,5 @@
- * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -119,7 +119,6 @@
main(gint argc, gchar **argv)
g_test_init(&argc, &argv, NULL);
g_test_add_func("/core/init_uninit", test_gplugin_init_uninit);
--- a/gplugin/tests/test-signals.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/tests/test-signals.c Fri Apr 10 03:05:31 2020 -0500
@@ -1,5 +1,5 @@
- * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com> * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,7 @@
+ gboolean unload_failed; } TestGPluginManagerSignalsData;
/******************************************************************************
@@ -116,6 +117,7 @@
test_gplugin_manager_signals_load_failed(
G_GNUC_UNUSED GObject *manager,
G_GNUC_UNUSED GPluginPlugin *plugin,
+ G_GNUC_UNUSED GError *error, TestGPluginManagerSignalsData *data = (TestGPluginManagerSignalsData *)d;
@@ -123,6 +125,18 @@
data->load_failed = TRUE;
+test_gplugin_manager_signals_unload_failed( + G_GNUC_UNUSED GObject *manager, + G_GNUC_UNUSED GPluginPlugin *plugin, + G_GNUC_UNUSED GError *error, + TestGPluginManagerSignalsData *data = (TestGPluginManagerSignalsData *)d; + data->unload_failed = TRUE; /******************************************************************************
*****************************************************************************/
@@ -132,7 +146,12 @@
GPluginPlugin *plugin = NULL;
GObject *manager = gplugin_manager_get_instance();
- TestGPluginManagerSignalsData data = {FALSE, FALSE, FALSE, FALSE, FALSE};
+ TestGPluginManagerSignalsData data = { gulong signals[] = {0, 0, 0, 0};
signals[0] = g_signal_connect(
@@ -182,7 +201,12 @@
GPluginPlugin *plugin = NULL;
GObject *manager = gplugin_manager_get_instance();
- TestGPluginManagerSignalsData data = {FALSE, FALSE, FALSE, FALSE, FALSE};
+ TestGPluginManagerSignalsData data = { gulong signals[] = {0, 0, 0, 0};
signals[0] = g_signal_connect(
@@ -229,7 +253,12 @@
GPluginPlugin *plugin = NULL;
GObject *manager = gplugin_manager_get_instance();
- TestGPluginManagerSignalsData data = {FALSE, FALSE, FALSE, FALSE, FALSE};
+ TestGPluginManagerSignalsData data = { gulong signals[] = {0, 0, 0, 0};
signals[0] = g_signal_connect(
@@ -279,8 +308,11 @@
GPluginPlugin *plugin = NULL;
GObject *manager = gplugin_manager_get_instance();
- TestGPluginManagerSignalsData data = {FALSE, FALSE, FALSE, FALSE, FALSE};
- gulong signals[] = {0, 0, 0, 0, 0};
+ TestGPluginManagerSignalsData data = { + gulong signals[] = {0, 0, 0, 0}; signals[0] = g_signal_connect(
@@ -306,13 +338,65 @@
g_signal_handler_disconnect(manager, signals[1]);
+test_gplugin_manager_signals_unload_failure(void) + GPluginPlugin *plugin = NULL; + GObject *manager = gplugin_manager_get_instance(); + TestGPluginManagerSignalsData data = { + .unload_failed = FALSE, + gulong signals[] = {0, 0, 0, 0}; + signals[0] = g_signal_connect( + G_CALLBACK(test_gplugin_manager_signals_normal_loading), + signals[1] = g_signal_connect( + G_CALLBACK(test_gplugin_manager_signals_normal_loaded), + signals[2] = g_signal_connect( + G_CALLBACK(test_gplugin_manager_signals_normal_unloading), + signals[3] = g_signal_connect( + "unload-plugin-failed", + G_CALLBACK(test_gplugin_manager_signals_unload_failed), + gplugin_manager_append_path(TEST_DIR); + gplugin_manager_refresh(); + plugin = gplugin_manager_find_plugin("gplugin/native-unload-failed"); + gplugin_manager_load_plugin(plugin, &error); + g_assert_no_error(error); + g_assert_true(data.loading); + g_assert_true(data.loaded); + gplugin_manager_unload_plugin(plugin, &error); + g_assert_error(error, GPLUGIN_DOMAIN, 0); + g_assert_true(data.unloading); + g_assert_true(data.unload_failed); + g_signal_handler_disconnect(manager, signals[0]); + g_signal_handler_disconnect(manager, signals[1]); /******************************************************************************
*****************************************************************************/
main(gint argc, gchar **argv)
g_test_init(&argc, &argv, NULL);
@@ -329,6 +413,9 @@
"/manager/signals/load-failed",
test_gplugin_manager_signals_load_failure);
+ "/manager/signals/unload-failed", + test_gplugin_manager_signals_unload_failure);