diff options
Diffstat (limited to '')
-rw-r--r-- | libgimpmodule/gimpmodule.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/libgimpmodule/gimpmodule.c b/libgimpmodule/gimpmodule.c new file mode 100644 index 0000000..83a5e90 --- /dev/null +++ b/libgimpmodule/gimpmodule.c @@ -0,0 +1,536 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpmodule.c + * (C) 1999 Austin Donnelly <austin@gimp.org> + * + * 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 3 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 "config.h" + +#include <string.h> + +#include <gio/gio.h> + +#include "libgimpbase/gimpbase.h" + +#include "gimpmodule.h" + +#include "libgimp/libgimp-intl.h" + + +/** + * SECTION: gimpmodule + * @title: GimpModule + * @short_description: A #GTypeModule subclass which implements module + * loading using #GModule. + * @see_also: #GModule, #GTypeModule + * + * A #GTypeModule subclass which implements module loading using #GModule. + **/ + + +enum +{ + MODIFIED, + LAST_SIGNAL +}; + + +static void gimp_module_finalize (GObject *object); + +static gboolean gimp_module_load (GTypeModule *module); +static void gimp_module_unload (GTypeModule *module); + +static gboolean gimp_module_open (GimpModule *module); +static gboolean gimp_module_close (GimpModule *module); +static void gimp_module_set_last_error (GimpModule *module, + const gchar *error_str); + + +G_DEFINE_TYPE (GimpModule, gimp_module, G_TYPE_TYPE_MODULE) + +#define parent_class gimp_module_parent_class + +static guint module_signals[LAST_SIGNAL]; + + +static void +gimp_module_class_init (GimpModuleClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (klass); + + module_signals[MODIFIED] = + g_signal_new ("modified", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpModuleClass, modified), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->finalize = gimp_module_finalize; + + module_class->load = gimp_module_load; + module_class->unload = gimp_module_unload; + + klass->modified = NULL; +} + +static void +gimp_module_init (GimpModule *module) +{ + module->filename = NULL; + module->verbose = FALSE; + module->state = GIMP_MODULE_STATE_ERROR; + module->on_disk = FALSE; + module->load_inhibit = FALSE; + + module->module = NULL; + module->info = NULL; + module->last_module_error = NULL; + + module->query_module = NULL; + module->register_module = NULL; +} + +static void +gimp_module_finalize (GObject *object) +{ + GimpModule *module = GIMP_MODULE (object); + + g_clear_pointer (&module->info, gimp_module_info_free); + g_clear_pointer (&module->last_module_error, g_free); + g_clear_pointer (&module->filename, g_free); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gimp_module_load (GTypeModule *module) +{ + GimpModule *gimp_module = GIMP_MODULE (module); + gpointer func; + + g_return_val_if_fail (gimp_module->filename != NULL, FALSE); + g_return_val_if_fail (gimp_module->module == NULL, FALSE); + + if (gimp_module->verbose) + g_print ("Loading module '%s'\n", + gimp_filename_to_utf8 (gimp_module->filename)); + + if (! gimp_module_open (gimp_module)) + return FALSE; + + if (! gimp_module_query_module (gimp_module)) + return FALSE; + + /* find the gimp_module_register symbol */ + if (! g_module_symbol (gimp_module->module, "gimp_module_register", &func)) + { + gimp_module_set_last_error (gimp_module, + "Missing gimp_module_register() symbol"); + + g_message (_("Module '%s' load error: %s"), + gimp_filename_to_utf8 (gimp_module->filename), + gimp_module->last_module_error); + + gimp_module_close (gimp_module); + + gimp_module->state = GIMP_MODULE_STATE_ERROR; + + return FALSE; + } + + gimp_module->register_module = func; + + if (! gimp_module->register_module (module)) + { + gimp_module_set_last_error (gimp_module, + "gimp_module_register() returned FALSE"); + + g_message (_("Module '%s' load error: %s"), + gimp_filename_to_utf8 (gimp_module->filename), + gimp_module->last_module_error); + + gimp_module_close (gimp_module); + + gimp_module->state = GIMP_MODULE_STATE_LOAD_FAILED; + + return FALSE; + } + + gimp_module->state = GIMP_MODULE_STATE_LOADED; + + return TRUE; +} + +static void +gimp_module_unload (GTypeModule *module) +{ + GimpModule *gimp_module = GIMP_MODULE (module); + + g_return_if_fail (gimp_module->module != NULL); + + if (gimp_module->verbose) + g_print ("Unloading module '%s'\n", + gimp_filename_to_utf8 (gimp_module->filename)); + + gimp_module_close (gimp_module); +} + + +/* public functions */ + +/** + * gimp_module_new: + * @filename: The filename of a loadable module. + * @load_inhibit: Pass %TRUE to exclude this module from auto-loading. + * @verbose: Pass %TRUE to enable debugging output. + * + * Creates a new #GimpModule instance. + * + * Return value: The new #GimpModule object. + **/ +GimpModule * +gimp_module_new (const gchar *filename, + gboolean load_inhibit, + gboolean verbose) +{ + GimpModule *module; + + g_return_val_if_fail (filename != NULL, NULL); + + module = g_object_new (GIMP_TYPE_MODULE, NULL); + + module->filename = g_strdup (filename); + module->load_inhibit = load_inhibit ? TRUE : FALSE; + module->verbose = verbose ? TRUE : FALSE; + module->on_disk = TRUE; + + if (! module->load_inhibit) + { + if (gimp_module_load (G_TYPE_MODULE (module))) + gimp_module_unload (G_TYPE_MODULE (module)); + } + else + { + if (verbose) + g_print ("Skipping module '%s'\n", + gimp_filename_to_utf8 (filename)); + + module->state = GIMP_MODULE_STATE_NOT_LOADED; + } + + return module; +} + +/** + * gimp_module_query_module: + * @module: A #GimpModule. + * + * Queries the module without actually registering any of the types it + * may implement. After successful query, the @info field of the + * #GimpModule struct will be available for further inspection. + * + * Return value: %TRUE on success. + **/ +gboolean +gimp_module_query_module (GimpModule *module) +{ + const GimpModuleInfo *info; + gboolean close_module = FALSE; + gpointer func; + + g_return_val_if_fail (GIMP_IS_MODULE (module), FALSE); + + if (! module->module) + { + if (! gimp_module_open (module)) + return FALSE; + + close_module = TRUE; + } + + /* find the gimp_module_query symbol */ + if (! g_module_symbol (module->module, "gimp_module_query", &func)) + { + gimp_module_set_last_error (module, + "Missing gimp_module_query() symbol"); + + g_message (_("Module '%s' load error: %s"), + gimp_filename_to_utf8 (module->filename), + module->last_module_error); + + gimp_module_close (module); + + module->state = GIMP_MODULE_STATE_ERROR; + return FALSE; + } + + module->query_module = func; + + if (module->info) + { + gimp_module_info_free (module->info); + module->info = NULL; + } + + info = module->query_module (G_TYPE_MODULE (module)); + + if (! info || info->abi_version != GIMP_MODULE_ABI_VERSION) + { + gimp_module_set_last_error (module, + info ? + "module ABI version does not match" : + "gimp_module_query() returned NULL"); + + g_message (_("Module '%s' load error: %s"), + gimp_filename_to_utf8 (module->filename), + module->last_module_error); + + gimp_module_close (module); + + module->state = GIMP_MODULE_STATE_ERROR; + return FALSE; + } + + module->info = gimp_module_info_copy (info); + + if (close_module) + return gimp_module_close (module); + + return TRUE; +} + +/** + * gimp_module_modified: + * @module: A #GimpModule. + * + * Emits the "modified" signal. Call it whenever you have modified the module + * manually (which you shouldn't do). + **/ +void +gimp_module_modified (GimpModule *module) +{ + g_return_if_fail (GIMP_IS_MODULE (module)); + + g_signal_emit (module, module_signals[MODIFIED], 0); +} + +/** + * gimp_module_set_load_inhibit: + * @module: A #GimpModule. + * @load_inhibit: Pass %TRUE to exclude this module from auto-loading. + * + * Sets the @load_inhibit property if the module. Emits "modified". + **/ +void +gimp_module_set_load_inhibit (GimpModule *module, + gboolean load_inhibit) +{ + g_return_if_fail (GIMP_IS_MODULE (module)); + + if (load_inhibit != module->load_inhibit) + { + module->load_inhibit = load_inhibit ? TRUE : FALSE; + + gimp_module_modified (module); + } +} + +/** + * gimp_module_state_name: + * @state: A #GimpModuleState. + * + * Returns the translated textual representation of a #GimpModuleState. + * The returned string must not be freed. + * + * Return value: The @state's name. + **/ +const gchar * +gimp_module_state_name (GimpModuleState state) +{ + static const gchar * const statenames[] = + { + N_("Module error"), + N_("Loaded"), + N_("Load failed"), + N_("Not loaded") + }; + + g_return_val_if_fail (state >= GIMP_MODULE_STATE_ERROR && + state <= GIMP_MODULE_STATE_NOT_LOADED, NULL); + + return gettext (statenames[state]); +} + +/** + * gimp_module_register_enum: + * @module: a module + * @name: the name of the new enum type + * @const_static_values: the enum values + * + * This function is deprecated! Use g_type_module_register_enum() instead. + * + * Return value: a new enum #GType + **/ +GType +gimp_module_register_enum (GTypeModule *module, + const gchar *name, + const GEnumValue *const_static_values) +{ + return g_type_module_register_enum (module, name, const_static_values); +} + +/** + * gimp_module_error_quark: + * + * This function is never called directly. Use GIMP_MODULE_ERROR() instead. + * + * Return value: the #GQuark that defines the GIMP module error domain. + * + * Since: 2.8 + **/ +GQuark +gimp_module_error_quark (void) +{ + return g_quark_from_static_string ("gimp-module-error-quark"); +} + + +/* private functions */ + +static gboolean +gimp_module_open (GimpModule *module) +{ + module->module = g_module_open (module->filename, 0); + + if (! module->module) + { + module->state = GIMP_MODULE_STATE_ERROR; + gimp_module_set_last_error (module, g_module_error ()); + + g_message (_("Module '%s' load error: %s"), + gimp_filename_to_utf8 (module->filename), + module->last_module_error); + + return FALSE; + } + + return TRUE; +} + +static gboolean +gimp_module_close (GimpModule *module) +{ + g_module_close (module->module); /* FIXME: error handling */ + module->module = NULL; + module->query_module = NULL; + module->register_module = NULL; + + module->state = GIMP_MODULE_STATE_NOT_LOADED; + + return TRUE; +} + +static void +gimp_module_set_last_error (GimpModule *module, + const gchar *error_str) +{ + if (module->last_module_error) + g_free (module->last_module_error); + + module->last_module_error = g_strdup (error_str); +} + + +/* GimpModuleInfo functions */ + +/** + * gimp_module_info_new: + * @abi_version: The #GIMP_MODULE_ABI_VERSION the module was compiled against. + * @purpose: The module's general purpose. + * @author: The module's author. + * @version: The module's version. + * @copyright: The module's copyright. + * @date: The module's release date. + * + * Creates a newly allocated #GimpModuleInfo struct. + * + * Return value: The new #GimpModuleInfo struct. + **/ +GimpModuleInfo * +gimp_module_info_new (guint32 abi_version, + const gchar *purpose, + const gchar *author, + const gchar *version, + const gchar *copyright, + const gchar *date) +{ + GimpModuleInfo *info = g_slice_new0 (GimpModuleInfo); + + info->abi_version = abi_version; + info->purpose = g_strdup (purpose); + info->author = g_strdup (author); + info->version = g_strdup (version); + info->copyright = g_strdup (copyright); + info->date = g_strdup (date); + + return info; +} + +/** + * gimp_module_info_copy: + * @info: The #GimpModuleInfo struct to copy. + * + * Copies a #GimpModuleInfo struct. + * + * Return value: The new copy. + **/ +GimpModuleInfo * +gimp_module_info_copy (const GimpModuleInfo *info) +{ + g_return_val_if_fail (info != NULL, NULL); + + return gimp_module_info_new (info->abi_version, + info->purpose, + info->author, + info->version, + info->copyright, + info->date); +} + +/** + * gimp_module_info_free: + * @info: The #GimpModuleInfo struct to free + * + * Frees the passed #GimpModuleInfo. + **/ +void +gimp_module_info_free (GimpModuleInfo *info) +{ + g_return_if_fail (info != NULL); + + g_free (info->purpose); + g_free (info->author); + g_free (info->version); + g_free (info->copyright); + g_free (info->date); + + g_slice_free (GimpModuleInfo, info); +} |