--- a/gplugin/gplugin-manager.c Sun Sep 25 00:06:03 2022 -0500
+++ b/gplugin/gplugin-manager.c Sun Sep 25 00:45:47 2022 -0500
@@ -22,10 +22,12 @@
#include <glib/gi18n-lib.h>
#include <gplugin/gplugin-core.h>
+#include <gplugin/gplugin-file-source.h> #include <gplugin/gplugin-file-tree.h>
#include <gplugin/gplugin-manager.h>
#include <gplugin/gplugin-native-loader.h>
#include <gplugin/gplugin-private.h>
+#include <gplugin/gplugin-source.h> * GPluginManagerForeachFunc:
@@ -70,10 +72,8 @@
- GHashTable *plugins_filename_view;
- GHashTable *loaders_by_extension;
@@ -95,15 +95,6 @@
/******************************************************************************
*****************************************************************************/
-gplugin_manager_str_hash(gconstpointer v)
gplugin_manager_remove_list_value(
G_GNUC_UNUSED gpointer k,
@@ -290,19 +281,9 @@
g_clear_pointer(&manager->plugins, g_hash_table_destroy);
- /* destroy the filename view */
- g_clear_pointer(&manager->plugins_filename_view, g_hash_table_destroy);
/* clean up our list of loaders */
g_clear_pointer(&manager->loaders, g_hash_table_destroy);
- /* free all the data in the loaders hash table and destroy it */
- g_hash_table_foreach_remove(
- manager->loaders_by_extension,
- gplugin_manager_remove_list_value,
- g_clear_pointer(&manager->loaders_by_extension, g_hash_table_destroy);
/* call the base class's destructor */
G_OBJECT_CLASS(gplugin_manager_parent_class)->finalize(obj);
@@ -497,31 +478,8 @@
g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
- /* the filename view is hash table keyed on the filename of the plugin with
- * a value of the plugin itself.
- manager->plugins_filename_view =
- g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
- /* The loaders_by_extension hash table is keyed on the supported extensions
- * of the loader. Which means that a loader that supports multiple
- * extensions will be in the table multiple times.
- * We deal with collisions by using a GSList for the value which will hold
- * references to instances of the actual loaders.
- * Storing this in this method allows us to quickly figure out which loader
- * to use by the filename and helps us to avoid iterating the loaders table
- manager->loaders_by_extension = g_hash_table_new_full(
- gplugin_manager_str_hash,
/******************************************************************************
@@ -806,7 +764,6 @@
GPluginLoader *found = NULL;
- GSList *l = NULL, *exts = NULL;
g_return_val_if_fail(GPLUGIN_IS_MANAGER(manager), FALSE);
@@ -826,39 +783,6 @@
g_hash_table_insert(manager->loaders, g_strdup(id), g_object_ref(loader));
- exts = gplugin_loader_get_supported_extensions(loader);
- for(l = exts; l; l = l->next) {
- GSList *existing = NULL, *ll = NULL;
- const gchar *ext = (const gchar *)l->data;
- /* grab any existing loaders that are registered for this type so that
- * we can prepend our loader. But before we add ours, we remove any
- * old copies we might have of ours.
- existing = g_hash_table_lookup(manager->loaders_by_extension, ext);
- for(ll = existing; ll; ll = ll->next) {
- GPluginLoader *iter = GPLUGIN_LOADER(ll->data);
- const gchar *ext_id = gplugin_loader_get_id(iter);
- if(g_str_equal(id, ext_id)) {
- existing = g_slist_remove(existing, iter);
- existing = g_slist_prepend(existing, g_object_ref(loader));
- /* Now insert the updated slist back into the hash table */
- manager->loaders_by_extension,
/* make a note that we need to refresh */
manager->refresh_needed = TRUE;
@@ -884,7 +808,6 @@
- GSList *l = NULL, *exts = NULL;
g_return_val_if_fail(GPLUGIN_IS_MANAGER(manager), FALSE);
@@ -904,47 +827,6 @@
- exts = gplugin_loader_get_supported_extensions(loader);
- for(l = exts; l; l = l->next) {
- const gchar *ext = NULL;
- ext = (const gchar *)exts->data;
- los = g_hash_table_lookup(manager->loaders_by_extension, ext);
- for(ll = los; ll; ll = ll->next) {
- GPluginLoader *lo = GPLUGIN_LOADER(ll->data);
- const gchar *lo_id = gplugin_loader_get_id(lo);
- /* check if this is not the loader we're looking for */
- if(!g_str_equal(id, lo_id)) {
- /* At this point, we're at the loader that we're removing. So we'll
- * remove it from the los SList. Then if the SList is empty, we
- * remove it from the hash table, otherwise we just update it.
- los = g_slist_remove(los, lo);
- manager->loaders_by_extension,
- g_hash_table_remove(manager->loaders_by_extension, ext);
- /* kill our ref to the loader */
- /* now move to the next extension to check */
/* Temporarily add a reference to loader so we can emit the signal if it
* was removed from our table correctly.
@@ -985,231 +867,23 @@
gplugin_manager_refresh(GPluginManager *manager)
- GList *error_messages = NULL, *l = NULL;
- gchar *error_message = NULL;
+ GPluginSource *file_source = NULL; g_return_if_fail(GPLUGIN_IS_MANAGER(manager));
- /* build a tree of all possible plugins */
- root = gplugin_file_tree_new(manager->paths->head);
+ file_source = gplugin_file_source_new(manager); manager->refresh_needed = TRUE;
while(manager->refresh_needed) {
- for(l = error_messages; l; l = l->next)
- g_list_free(error_messages);
manager->refresh_needed = FALSE;
- for(dir = root->children; dir; dir = dir->next) {
- GPluginFileTreeEntry *e = dir->data;
- const gchar *path = e->filename;
- for(file = dir->children; file; file = file->next) {
- GPluginPlugin *plugin = NULL;
- GPluginLoader *loader = NULL;
- gchar *filename = NULL;
- e = (GPluginFileTreeEntry *)file->data;
- /* Build the path and see if we need to probe it! */
- filename = g_build_filename(path, e->filename, NULL);
- plugin = g_hash_table_lookup(
- manager->plugins_filename_view,
- if(plugin && GPLUGIN_IS_PLUGIN(plugin)) {
- GPluginPluginState state = gplugin_plugin_get_state(plugin);
- /* The plugin is in our "view", check its state. If it's
- * queried or loaded, move on to the next one.
- if(state == GPLUGIN_PLUGIN_STATE_QUERIED ||
- state == GPLUGIN_PLUGIN_STATE_LOADED) {
- /* grab the list of loaders for this extension */
- l = g_hash_table_lookup(
- manager->loaders_by_extension,
- for(; l; l = l->next) {
- if(!GPLUGIN_IS_LOADER(l->data)) {
- loader = GPLUGIN_LOADER(l->data);
- /* Try to probe the plugin with the current loader */
- gplugin_loader_query_plugin(loader, filename, &error);
- /* Check the GError, if it's set, output its message and
- error_message = g_strdup_printf(
- _("failed to query '%s' with "
- G_OBJECT_TYPE_NAME(loader),
- g_list_prepend(error_messages, error_message);
- /* if the plugin instance is good, then break out of this
- if(GPLUGIN_IS_PLUGIN(plugin)) {
- g_object_unref(G_OBJECT(plugin));
- /* check if our plugin instance is good. If it's not good we
- * don't need to do anything but free the filename which we'll
- if(GPLUGIN_IS_PLUGIN(plugin)) {
- /* we have a good plugin, huzzah! We need to add it to our
- * "view" as well as the main plugin hash table.
- /* we want the internal filename from the plugin to avoid
- * duplicate memory, so we need to grab it for the "view".
- gchar *real_filename = gplugin_plugin_get_filename(plugin);
- /* we also need the GPluginPluginInfo to get the plugin's
- * ID for the key in our main hash table.
- GPluginPluginInfo *info = gplugin_plugin_get_info(plugin);
- const gchar *id = gplugin_plugin_info_get_id(info);
- GSList *l = NULL, *ll = NULL;
- /* throw a warning if the info->id is NULL */
- error_message = g_strdup_printf(
- _("Plugin %s has a NULL id."),
- g_object_unref(G_OBJECT(info));
- g_list_prepend(error_messages, error_message);
- /* now insert into our view */
- manager->plugins_filename_view,
- g_object_ref(G_OBJECT(plugin)));
- /* Grab the list of plugins with our id and prepend the new
- * plugin to it before updating it.
- l = g_hash_table_lookup(manager->plugins, id);
- for(ll = l; ll; ll = ll->next) {
- GPluginPlugin *splugin = GPLUGIN_PLUGIN(ll->data);
- gchar *sfilename = gplugin_plugin_get_filename(splugin);
- if(!g_strcmp0(real_filename, sfilename))
- l = g_slist_prepend(l, g_object_ref(plugin));
- g_hash_table_insert(manager->plugins, g_strdup(id), l);
- /* check if the plugin is supposed to be loaded on query,
- if(gplugin_plugin_info_get_load_on_query(info)) {
- gplugin_loader_load_plugin(loader, plugin, &error);
- error_message = g_strdup_printf(
- _("failed to load %s during query: %s"),
- (error) ? error->message : _("Unknown"));
- g_list_prepend(error_messages, error_message);
- /* if errors is greater than 0 set
- * manager->refresh_needed to TRUE.
- manager->refresh_needed = TRUE;
- g_object_unref(G_OBJECT(info));
- /* since the plugin is now stored in our hash tables we
- * need to remove this function's reference to it.
- g_object_unref(G_OBJECT(plugin));
+ if(gplugin_source_scan(file_source)) { + manager->refresh_needed = TRUE;
- error_messages = g_list_reverse(error_messages);
- for(l = error_messages; l; l = l->next) {
- g_warning("%s", (gchar *)l->data);
- g_list_free(error_messages);
- /* free the file tree */
- gplugin_file_tree_free(root);
+ g_clear_object(&file_source); @@ -1813,6 +1487,34 @@
+ * gplugin_manager_add_plugin: + * @manager: The instance. + * @id: The id of the plugin to add. + * @plugin: The plugin to add. + * Adds @plugin to @manager with @id. This should only be called by + * [iface@GPlugin.Source] implementations. +gplugin_manager_add_plugin( + GPluginManager *manager, + GSList *plugins = NULL; + g_return_if_fail(GPLUGIN_IS_MANAGER(manager)); + g_return_if_fail(id != NULL); + g_return_if_fail(GPLUGIN_IS_PLUGIN(plugin)); + plugins = g_hash_table_lookup(manager->plugins, id); + plugins = g_slist_prepend(plugins, g_object_ref(plugin)); + g_hash_table_insert(manager->plugins, g_strdup(id), plugins); * gplugin_manager_get_default:
* Gets the default plugin manager in GPlugin.
--- a/gplugin/gplugin-private.h Sun Sep 25 00:06:03 2022 -0500
+++ b/gplugin/gplugin-private.h Sun Sep 25 00:45:47 2022 -0500
@@ -24,6 +24,7 @@
#define GPLUGIN_GLOBAL_HEADER_INSIDE
+#include <gplugin/gplugin-manager.h> #include <gplugin/gplugin-plugin-info.h>
#include <gplugin/gplugin-plugin.h>
#undef GPLUGIN_GLOBAL_HEADER_INSIDE
@@ -39,6 +40,12 @@
const GValue *handler_return,
+void gplugin_manager_add_plugin( + GPluginManager *manager, + GPluginPlugin *plugin); #endif /* GPLUGIN_PRIVATE_H */
--- a/gplugin/meson.build Sun Sep 25 00:06:03 2022 -0500
+++ b/gplugin/meson.build Sun Sep 25 00:45:47 2022 -0500
@@ -34,11 +34,13 @@
GPLUGIN_PRIVATE_HEADERS = [
+ 'gplugin-file-source.h', GPLUGIN_PRIVATE_SOURCES = [
+ 'gplugin-file-source.c', --- a/gplugin/tests/test-native-loader.c Sun Sep 25 00:06:03 2022 -0500
+++ b/gplugin/tests/test-native-loader.c Sun Sep 25 00:45:47 2022 -0500
@@ -80,7 +80,7 @@
g_test_trap_subprocess("/loaders/native/error/query/subprocess", 0, 0);
- g_test_trap_assert_failed();
+ g_test_trap_assert_stderr("*expected error*"); /******************************************************************************