gimp/libgimpmodule/gimpmodule.c

421 lines
11 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpmoduleinfo.c
* (C) 1999 Austin Donnelly <austin@gimp.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <glib-object.h>
#include "libgimp/gimpmodule.h"
#include "core-types.h"
#include "gimpmarshal.h"
#include "gimpmoduleinfo.h"
#include "libgimp/gimpintl.h"
enum
{
MODIFIED,
LAST_SIGNAL
};
static void gimp_module_info_class_init (GimpModuleInfoObjClass *klass);
static void gimp_module_info_init (GimpModuleInfoObj *mod);
static void gimp_module_info_finalize (GObject *object);
static gsize gimp_module_info_get_memsize (GimpObject *object);
static guint module_info_signals[LAST_SIGNAL];
static GimpObjectClass *parent_class = NULL;
GType
gimp_module_info_get_type (void)
{
static GType module_info_type = 0;
if (! module_info_type)
{
static const GTypeInfo module_info_info =
{
sizeof (GimpModuleInfoObjClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) gimp_module_info_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GimpModuleInfoObj),
0, /* n_preallocs */
(GInstanceInitFunc) gimp_module_info_init,
};
module_info_type = g_type_register_static (GIMP_TYPE_OBJECT,
"GimpModuleInfoObj",
&module_info_info, 0);
}
return module_info_type;
}
static void
gimp_module_info_class_init (GimpModuleInfoObjClass *klass)
{
GObjectClass *object_class;
GimpObjectClass *gimp_object_class;
object_class = G_OBJECT_CLASS (klass);
gimp_object_class = GIMP_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
module_info_signals[MODIFIED] =
g_signal_new ("modified",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpModuleInfoObjClass, modified),
NULL, NULL,
gimp_marshal_VOID__VOID,
G_TYPE_NONE, 0);
object_class->finalize = gimp_module_info_finalize;
gimp_object_class->get_memsize = gimp_module_info_get_memsize;
klass->modified = NULL;
}
static void
gimp_module_info_init (GimpModuleInfoObj *module_info)
{
module_info->fullpath = NULL;
module_info->state = GIMP_MODULE_STATE_ERROR;
module_info->on_disk = FALSE;
module_info->load_inhibit = FALSE;
module_info->refs = 0;
module_info->info = NULL;
module_info->module = NULL;
module_info->last_module_error = NULL;
module_info->init = NULL;
module_info->unload = NULL;
}
static void
gimp_module_info_finalize (GObject *object)
{
GimpModuleInfoObj *mod;
mod = GIMP_MODULE_INFO (object);
/* if this trips, then we're onto some serious lossage in a moment */
g_return_if_fail (mod->refs == 0);
if (mod->last_module_error)
{
g_free (mod->last_module_error);
mod->last_module_error = NULL;
}
if (mod->fullpath)
{
g_free (mod->fullpath);
mod->fullpath = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gsize
gimp_module_info_get_memsize (GimpObject *object)
{
GimpModuleInfoObj *module_info;
gsize memsize = 0;
module_info = GIMP_MODULE_INFO (object);
if (module_info->fullpath)
memsize += strlen (module_info->fullpath) + 1;
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object);
}
GimpModuleInfoObj *
gimp_module_info_new (const gchar *filename)
{
GimpModuleInfoObj *module_info;
g_return_val_if_fail (filename != NULL, NULL);
module_info = g_object_new (GIMP_TYPE_MODULE_INFO, NULL);
module_info->fullpath = g_strdup (filename);
module_info->on_disk = TRUE;
return module_info;
}
void
gimp_module_info_modified (GimpModuleInfoObj *module_info)
{
g_return_if_fail (GIMP_IS_MODULE_INFO (module_info));
g_signal_emit (G_OBJECT (module_info), module_info_signals[MODIFIED], 0);
}
void
gimp_module_info_set_load_inhibit (GimpModuleInfoObj *module_info,
const gchar *inhibit_list)
{
gchar *p;
gint pathlen;
const gchar *start;
const gchar *end;
g_return_if_fail (GIMP_IS_MODULE_INFO (module_info));
g_return_if_fail (module_info->fullpath != NULL);
module_info->load_inhibit = FALSE;
if (! inhibit_list || ! strlen (inhibit_list))
return;
p = strstr (inhibit_list, module_info->fullpath);
if (!p)
return;
/* we have a substring, but check for colons either side */
start = p;
while (start != inhibit_list && *start != G_SEARCHPATH_SEPARATOR)
start--;
if (*start == G_SEARCHPATH_SEPARATOR)
start++;
end = strchr (p, G_SEARCHPATH_SEPARATOR);
if (! end)
end = inhibit_list + strlen (inhibit_list);
pathlen = strlen (module_info->fullpath);
if ((end - start) == pathlen)
module_info->load_inhibit = TRUE;
}
static void
gimp_module_info_set_last_error (GimpModuleInfoObj *module_info,
const gchar *error_str)
{
if (module_info->last_module_error)
g_free (module_info->last_module_error);
module_info->last_module_error = g_strdup (error_str);
}
/*
* FIXME: currently this will fail badly on EMX
*/
#ifdef __EMX__
extern void gimp_color_selector_register (void);
extern void gimp_color_selector_unregister (void);
extern void dialog_register (void);
extern void dialog_unregister (void);
static struct main_funcs_struc
{
gchar *name;
void (* func) (void);
}
gimp_main_funcs[] =
{
{ "gimp_color_selector_register", gimp_color_selector_register },
{ "gimp_color_selector_unregister", gimp_color_selector_unregister },
{ "dialog_register", dialog_register },
{ "dialog_unregister", dialog_unregister },
{ NULL, NULL }
};
#endif
void
gimp_module_info_module_load (GimpModuleInfoObj *module_info,
gboolean verbose)
{
gpointer symbol;
g_return_if_fail (GIMP_IS_MODULE_INFO (module_info));
g_return_if_fail (module_info->fullpath != NULL);
g_return_if_fail (module_info->module == NULL);
module_info->module = g_module_open (module_info->fullpath,
G_MODULE_BIND_LAZY);
if (! module_info->module)
{
module_info->state = GIMP_MODULE_STATE_ERROR;
gimp_module_info_set_last_error (module_info, g_module_error ());
if (verbose)
g_message (_("Module '%s' load error:\n%s"),
module_info->fullpath, module_info->last_module_error);
return;
}
#ifdef __EMX__
if (g_module_symbol (module_info->module, "gimp_main_funcs", &symbol))
{
*(struct main_funcs_struc **) symbol = gimp_main_funcs;
}
#endif
/* find the module_init symbol */
if (! g_module_symbol (module_info->module, "module_init", &symbol))
{
module_info->state = GIMP_MODULE_STATE_ERROR;
gimp_module_info_set_last_error (module_info,
_("Missing module_init() symbol"));
if (verbose)
g_message (_("Module '%s' load error:\n%s"),
module_info->fullpath, module_info->last_module_error);
g_module_close (module_info->module);
module_info->module = NULL;
return;
}
module_info->init = symbol;
/* loaded modules are assumed to have a ref of 1 */
gimp_module_info_module_ref (module_info);
/* run module's initialisation */
if (module_info->init (&module_info->info) == GIMP_MODULE_UNLOAD)
{
module_info->state = GIMP_MODULE_STATE_LOAD_FAILED;
gimp_module_info_module_unref (module_info);
module_info->info = NULL;
return;
}
/* module is now happy */
module_info->state = GIMP_MODULE_STATE_LOADED_OK;
/* do we have an unload function? */
if (g_module_symbol (module_info->module, "module_unload", &symbol))
{
module_info->unload = symbol;
}
}
static void
gimp_module_info_module_unload_completed_callback (gpointer data)
{
GimpModuleInfoObj *module_info;
module_info = (GimpModuleInfoObj *) data;
g_return_if_fail (module_info->state == GIMP_MODULE_STATE_UNLOAD_REQUESTED);
/* lose the ref we gave this module when we loaded it,
* since the module's now happy to be unloaded.
*/
gimp_module_info_module_unref (module_info);
module_info->info = NULL;
module_info->state = GIMP_MODULE_STATE_UNLOADED_OK;
gimp_module_info_modified (module_info);
}
static gboolean
gimp_module_info_module_idle_unref (gpointer data)
{
GimpModuleInfoObj *module_info;
module_info = (GimpModuleInfoObj *) data;
gimp_module_info_module_unref (module_info);
return FALSE;
}
void
gimp_module_info_module_unload (GimpModuleInfoObj *module_info,
gboolean verbose)
{
g_return_if_fail (GIMP_IS_MODULE_INFO (module_info));
g_return_if_fail (module_info->module != NULL);
g_return_if_fail (module_info->unload != NULL);
if (module_info->state == GIMP_MODULE_STATE_UNLOAD_REQUESTED)
return;
module_info->state = GIMP_MODULE_STATE_UNLOAD_REQUESTED;
/* Send the unload request. Need to ref the module so we don't
* accidentally unload it while this call is in progress (eg if the
* callback is called before the unload function returns).
*/
gimp_module_info_module_ref (module_info);
module_info->unload (module_info->info->shutdown_data,
gimp_module_info_module_unload_completed_callback,
module_info);
g_idle_add (gimp_module_info_module_idle_unref, module_info);
}
void
gimp_module_info_module_ref (GimpModuleInfoObj *module_info)
{
g_return_if_fail (GIMP_IS_MODULE_INFO (module_info));
g_return_if_fail (module_info->refs >= 0);
g_return_if_fail (module_info->module != NULL);
module_info->refs++;
}
void
gimp_module_info_module_unref (GimpModuleInfoObj *module_info)
{
g_return_if_fail (GIMP_IS_MODULE_INFO (module_info));
g_return_if_fail (module_info->refs > 0);
g_return_if_fail (module_info->module != NULL);
module_info->refs--;
if (module_info->refs == 0)
{
g_module_close (module_info->module);
module_info->module = NULL;
}
}