* 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 * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <https://www.gnu.org/licenses/>. #include <gplugin/gplugin-core.h> #include <gplugin/gplugin-loader.h> * @short_description: Abstract class for loading plugins * GPluginLoader defines the base behavior for loaders of all languages. * The standard _get_type macro for #GPluginLoader. * An abstract class that should not be accessed directly. * @supported_extensions: The supported_extensions vfunc returns a #GList of * file extensions that this loader supports without the * leading dot. For example: 'so', 'dll', 'py', etc. * @query: The query vfunc is called when the plugin manager needs to query a * plugin that has a file extension from @supported_extensions. * @load: The load vfunc is called when the plugin manager wants to load a * plugin that was previously queried by this loader. * @unload: The unload vfunc is called when the plugin manager wants to unload * a previously loaded plugin from this loader. * #GPluginLoaderClass defines the behavior for loading plugins. static GParamSpec *properties[N_PROPERTIES] = { G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE( /****************************************************************************** *****************************************************************************/ gplugin_loader_set_id(GPluginLoader *loader, const gchar *id) GPluginLoaderPrivate *priv = gplugin_loader_get_instance_private(loader); g_object_notify_by_pspec(G_OBJECT(loader), properties[PROP_ID]); /****************************************************************************** *****************************************************************************/ gplugin_loader_get_property( GPluginLoader *loader = GPLUGIN_LOADER(obj); g_value_set_string(value, gplugin_loader_get_id(loader)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); gplugin_loader_set_property( GPluginLoader *loader = GPLUGIN_LOADER(obj); gplugin_loader_set_id(loader, g_value_get_string(value)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); gplugin_loader_finalize(GObject *obj) GPluginLoader *loader = NULL; GPluginLoaderPrivate *priv = NULL; loader = GPLUGIN_LOADER(obj); priv = gplugin_loader_get_instance_private(loader); g_clear_pointer(&priv->id, g_free); G_OBJECT_CLASS(gplugin_loader_parent_class)->finalize(obj); gplugin_loader_init(G_GNUC_UNUSED GPluginLoader *loader) gplugin_loader_class_init(G_GNUC_UNUSED GPluginLoaderClass *klass) GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->get_property = gplugin_loader_get_property; obj_class->set_property = gplugin_loader_set_property; obj_class->finalize = gplugin_loader_finalize; * The identifier of the loader. properties[PROP_ID] = g_param_spec_string( "The identifier of the loader", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, N_PROPERTIES, properties); /****************************************************************************** *****************************************************************************/ * @loader: The #GPluginLoader instance. * Gets the identifier of @loader. * Returns: The ID of @loader. gplugin_loader_get_id(GPluginLoader *loader) GPluginLoaderPrivate *priv = NULL; g_return_val_if_fail(GPLUGIN_IS_LOADER(loader), NULL); priv = gplugin_loader_get_instance_private(loader); * gplugin_loader_query_plugin: * @loader: The #GPluginLoader instance performing the query. * @filename: The filename to query. * @error: (nullable): The return location for a #GError, or %NULL. * This function is called by the plugin manager to ask @loader to query * @filename and determine if it's a usable plugin. * Return value: (transfer full): A #GPluginPlugin instance or %NULL on gplugin_loader_query_plugin( GPluginLoaderClass *klass = NULL; GPluginPlugin *plugin = NULL; GError *real_error = NULL; g_return_val_if_fail(loader != NULL, NULL); g_return_val_if_fail(GPLUGIN_IS_LOADER(loader), NULL); g_return_val_if_fail(filename, NULL); g_return_val_if_fail(error != NULL, NULL); klass = GPLUGIN_LOADER_GET_CLASS(loader); if(klass != NULL && klass->query != NULL) { plugin = klass->query(loader, filename, &real_error); if(!GPLUGIN_IS_PLUGIN(plugin)) { real_error = g_error_new_literal( "Failed to query plugin : unknown"); g_propagate_error(error, real_error); /* If the plugin successfully queried but returned an error, ignore the g_clear_error(&real_error); /* Likewise, make sure the plugin's error is set to NULL. */ g_object_set(G_OBJECT(plugin), "error", NULL, NULL); gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_QUERIED); * gplugin_loader_load_plugin: * @loader: The #GPluginLoader instance performing the load. * @plugin: The #GPluginPlugin instance to load. * @error: (nullable): The return location for a #GError, or %NULL. * This function is called by the plugin manager to ask @loader to load * Return value: %TRUE if @plugin was loaded successfully, %FALSE otherwise. gplugin_loader_load_plugin( GPluginLoaderClass *klass = NULL; GError *real_error = NULL; g_return_val_if_fail(loader != NULL, FALSE); g_return_val_if_fail(GPLUGIN_IS_LOADER(loader), FALSE); g_return_val_if_fail(GPLUGIN_IS_PLUGIN(plugin), FALSE); /* if the plugin is already loaded there's nothing for us to do */ if(gplugin_plugin_get_state(plugin) == GPLUGIN_PLUGIN_STATE_LOADED) { klass = GPLUGIN_LOADER_GET_CLASS(loader); if(klass != NULL && klass->load != NULL) { ret = klass->load(loader, plugin, &real_error); real_error = g_error_new_literal( "Failed to load plugin : unknown"); /* Set the error on the plugin as well. This has to be before we * propagate the error, because error is invalidate at that point. g_object_set(plugin, "error", real_error, NULL); /* Set the state after the error is set, because people might connect * to the notify signal on the state property. gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_LOAD_FAILED); g_propagate_error(error, real_error); /* If the plugin successfully loaded but returned an error, ignore the g_clear_error(&real_error); /* Likewise, make sure the plugin's error is set to NULL. */ g_object_set(G_OBJECT(plugin), "error", NULL, NULL); gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_LOADED); * gplugin_loader_unload_plugin: * @loader: The #GPluginLoader instance performing the unload. * @plugin: The #GPluginPlugin instance to unload. * @error: (nullable): The return location for a #GError, or %NULL. * This function is called by the plugin manager to ask @loader to unload * Return value: %TRUE if @plugin was unloaded successfully, %FALSE otherwise. gplugin_loader_unload_plugin( GPluginLoaderClass *klass = NULL; GError *real_error = NULL; g_return_val_if_fail(loader != NULL, FALSE); g_return_val_if_fail(GPLUGIN_IS_LOADER(loader), FALSE); g_return_val_if_fail(GPLUGIN_IS_PLUGIN(plugin), FALSE); if(gplugin_plugin_get_state(plugin) != GPLUGIN_PLUGIN_STATE_LOADED) { klass = GPLUGIN_LOADER_GET_CLASS(loader); if(klass != NULL && klass->unload != NULL) { ret = klass->unload(loader, plugin, &real_error); real_error = g_error_new_literal( "Failed to unload plugin : unknown"); g_object_set(G_OBJECT(plugin), "error", real_error, NULL); /* Set the state after the error is set, because people might connect * to the notify signal on the state property. gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED); g_propagate_error(error, real_error); /* If the plugin successfully unloaded but returned an error, ignore the gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_QUERIED); * gplugin_loader_get_supported_extensions: * @loader: The #GPluginLoader instance. * Returns a #GSList of strings containing the extensions that the loader * supports. Each extension should not include the dot. For example: so, * Return value: (element-type utf8) (transfer container): A #GSList of * extensions that the loader supports. gplugin_loader_get_supported_extensions(GPluginLoader *loader) GPluginLoaderClass *klass = NULL; g_return_val_if_fail(GPLUGIN_IS_LOADER(loader), NULL); klass = GPLUGIN_LOADER_GET_CLASS(loader); if(klass != NULL && klass->supported_extensions) { return klass->supported_extensions(loader);