mirror of https://github.com/GNOME/gimp.git
499 lines
14 KiB
C
499 lines
14 KiB
C
/* LIBGIMP - The GIMP Library
|
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
|
*
|
|
* 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, 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 "libgimpbase/gimpbase.h"
|
|
|
|
#include "gimpmoduletypes.h"
|
|
|
|
#include "gimpmodule.h"
|
|
#include "gimpmoduledb.h"
|
|
|
|
|
|
enum
|
|
{
|
|
ADD,
|
|
REMOVE,
|
|
MODULE_MODIFIED,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
|
|
/* #define DUMP_DB 1 */
|
|
|
|
|
|
static void gimp_module_db_class_init (GimpModuleDBClass *klass);
|
|
static void gimp_module_db_init (GimpModuleDB *db);
|
|
|
|
static void gimp_module_db_finalize (GObject *object);
|
|
|
|
static void gimp_module_db_module_initialize (const GimpDatafileData *file_data,
|
|
gpointer user_data);
|
|
|
|
static GimpModule * gimp_module_db_module_find_by_path (GimpModuleDB *db,
|
|
const char *fullpath);
|
|
|
|
#ifdef DUMP_DB
|
|
static void gimp_module_db_dump_module (gpointer data,
|
|
gpointer user_data);
|
|
#endif
|
|
|
|
static void gimp_module_db_module_on_disk_func (gpointer data,
|
|
gpointer user_data);
|
|
static void gimp_module_db_module_remove_func (gpointer data,
|
|
gpointer user_data);
|
|
static void gimp_module_db_module_modified (GimpModule *module,
|
|
GimpModuleDB *db);
|
|
|
|
|
|
static GObjectClass *parent_class = NULL;
|
|
|
|
static guint db_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
GType
|
|
gimp_module_db_get_type (void)
|
|
{
|
|
static GType db_type = 0;
|
|
|
|
if (! db_type)
|
|
{
|
|
static const GTypeInfo db_info =
|
|
{
|
|
sizeof (GimpModuleDBClass),
|
|
NULL, /* base_init */
|
|
NULL, /* base_finalize */
|
|
(GClassInitFunc) gimp_module_db_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (GimpModuleDB),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) gimp_module_db_init,
|
|
};
|
|
|
|
db_type = g_type_register_static (G_TYPE_OBJECT,
|
|
"GimpModuleDB",
|
|
&db_info, 0);
|
|
}
|
|
|
|
return db_type;
|
|
}
|
|
|
|
static void
|
|
gimp_module_db_class_init (GimpModuleDBClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
db_signals[ADD] =
|
|
g_signal_new ("add",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (GimpModuleDBClass, add),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
GIMP_TYPE_MODULE);
|
|
|
|
db_signals[REMOVE] =
|
|
g_signal_new ("remove",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (GimpModuleDBClass, remove),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
GIMP_TYPE_MODULE);
|
|
|
|
db_signals[MODULE_MODIFIED] =
|
|
g_signal_new ("module-modified",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (GimpModuleDBClass, module_modified),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
GIMP_TYPE_MODULE);
|
|
|
|
object_class->finalize = gimp_module_db_finalize;
|
|
|
|
klass->add = NULL;
|
|
klass->remove = NULL;
|
|
}
|
|
|
|
static void
|
|
gimp_module_db_init (GimpModuleDB *db)
|
|
{
|
|
db->modules = NULL;
|
|
db->load_inhibit = NULL;
|
|
db->verbose = FALSE;
|
|
}
|
|
|
|
static void
|
|
gimp_module_db_finalize (GObject *object)
|
|
{
|
|
GimpModuleDB *db = GIMP_MODULE_DB (object);
|
|
|
|
if (db->modules)
|
|
{
|
|
g_list_free (db->modules);
|
|
db->modules = NULL;
|
|
}
|
|
|
|
if (db->load_inhibit)
|
|
{
|
|
g_free (db->load_inhibit);
|
|
db->load_inhibit = NULL;
|
|
}
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
/**
|
|
* gimp_module_db_new:
|
|
* @verbose: Pass %TRUE to enable debugging output.
|
|
*
|
|
* Creates a new #GimpModuleDB instance. The @verbose parameter will be
|
|
* passed to the created #GimpModule instances using gimp_module_new().
|
|
*
|
|
* Return value: The new #GimpModuleDB instance.
|
|
**/
|
|
GimpModuleDB *
|
|
gimp_module_db_new (gboolean verbose)
|
|
{
|
|
GimpModuleDB *db;
|
|
|
|
db = g_object_new (GIMP_TYPE_MODULE_DB, NULL);
|
|
|
|
db->verbose = verbose ? TRUE : FALSE;
|
|
|
|
return db;
|
|
}
|
|
|
|
static gboolean
|
|
is_in_inhibit_list (const gchar *filename,
|
|
const gchar *inhibit_list)
|
|
{
|
|
gchar *p;
|
|
gint pathlen;
|
|
const gchar *start;
|
|
const gchar *end;
|
|
|
|
if (! inhibit_list || ! strlen (inhibit_list))
|
|
return FALSE;
|
|
|
|
p = strstr (inhibit_list, filename);
|
|
if (!p)
|
|
return FALSE;
|
|
|
|
/* 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 (filename);
|
|
|
|
if ((end - start) == pathlen)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* gimp_module_db_set_load_inhibit:
|
|
* @db: A #GimpModuleDB.
|
|
* @load_inhibit: A #G_SEARCHPATH_SEPARATOR delimited list of module
|
|
* filenames to exclude from auto-loading.
|
|
*
|
|
* Sets the @load_inhibit flag for all #GimpModule's which are kept
|
|
* by @db (using gimp_module_set_load_inhibit()).
|
|
**/
|
|
void
|
|
gimp_module_db_set_load_inhibit (GimpModuleDB *db,
|
|
const gchar *load_inhibit)
|
|
{
|
|
GList *list;
|
|
|
|
g_return_if_fail (GIMP_IS_MODULE_DB (db));
|
|
|
|
if (db->load_inhibit)
|
|
g_free (db->load_inhibit);
|
|
|
|
db->load_inhibit = g_strdup (load_inhibit);
|
|
|
|
for (list = db->modules; list; list = g_list_next (list))
|
|
{
|
|
GimpModule *module = list->data;
|
|
|
|
gimp_module_set_load_inhibit (module,
|
|
is_in_inhibit_list (module->filename,
|
|
load_inhibit));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gimp_module_db_get_load_inhibit:
|
|
* @db: A #GimpModuleDB.
|
|
*
|
|
* Return the #G_SEARCHPATH_SEPARATOR selimited list of module filenames
|
|
* which are excluded from auto-loading.
|
|
*
|
|
* Return value: the @db's @load_inhibit string.
|
|
**/
|
|
const gchar *
|
|
gimp_module_db_get_load_inhibit (GimpModuleDB *db)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_MODULE_DB (db), NULL);
|
|
|
|
return db->load_inhibit;
|
|
}
|
|
|
|
/**
|
|
* gimp_module_db_load:
|
|
* @db: A #GimpModuleDB.
|
|
* @module_path: A #G_SEARCHPATH_SEPARATOR delimited list of directories
|
|
* to load modules from.
|
|
*
|
|
* Scans the directories contained in @module_path using
|
|
* gimp_datafiles_read_directories() and creates a #GimpModule
|
|
* instance for every loadable module contained in the directories.
|
|
**/
|
|
void
|
|
gimp_module_db_load (GimpModuleDB *db,
|
|
const gchar *module_path)
|
|
{
|
|
g_return_if_fail (GIMP_IS_MODULE_DB (db));
|
|
g_return_if_fail (module_path != NULL);
|
|
|
|
if (g_module_supported ())
|
|
gimp_datafiles_read_directories (module_path,
|
|
G_FILE_TEST_EXISTS,
|
|
gimp_module_db_module_initialize,
|
|
db);
|
|
|
|
#ifdef DUMP_DB
|
|
g_list_foreach (db->modules, gimp_module_db_dump_module, NULL);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* gimp_module_db_refresh:
|
|
* @db: A #GimpModuleDB.
|
|
* @module_path: A #G_SEARCHPATH_SEPARATOR delimited list of directories
|
|
* to load modules from.
|
|
*
|
|
* Does the same as gimp_module_db_load(), plus removes all #GimpModule
|
|
* instances whose modules have been deleted from disk.
|
|
*
|
|
* Note that the #GimpModule's will just be removed from the internal
|
|
* list and not freed as this is not possible with #GTypeModule
|
|
* instances which actually implement types.
|
|
**/
|
|
void
|
|
gimp_module_db_refresh (GimpModuleDB *db,
|
|
const gchar *module_path)
|
|
{
|
|
GList *kill_list = NULL;
|
|
|
|
g_return_if_fail (GIMP_IS_MODULE_DB (db));
|
|
g_return_if_fail (module_path != NULL);
|
|
|
|
/* remove modules we don't have on disk anymore */
|
|
g_list_foreach (db->modules,
|
|
gimp_module_db_module_on_disk_func,
|
|
&kill_list);
|
|
g_list_foreach (kill_list,
|
|
gimp_module_db_module_remove_func,
|
|
db);
|
|
g_list_free (kill_list);
|
|
|
|
/* walk filesystem and add new things we find */
|
|
gimp_datafiles_read_directories (module_path,
|
|
G_FILE_TEST_EXISTS,
|
|
gimp_module_db_module_initialize,
|
|
db);
|
|
}
|
|
|
|
/* name must be of the form lib*.so (Unix) or *.dll (Win32) */
|
|
static gboolean
|
|
valid_module_name (const gchar *filename)
|
|
{
|
|
gchar *basename = g_path_get_basename (filename);
|
|
|
|
#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
|
|
if (strncmp (basename, "lib", 3))
|
|
goto no_module;
|
|
|
|
if (! gimp_datafiles_check_extension (basename, ".so"))
|
|
goto no_module;
|
|
#else
|
|
if (! gimp_datafiles_check_extension (basename, ".dll"))
|
|
goto no_module;
|
|
#endif
|
|
|
|
g_free (basename);
|
|
|
|
return TRUE;
|
|
|
|
no_module:
|
|
g_free (basename);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gimp_module_db_module_initialize (const GimpDatafileData *file_data,
|
|
gpointer user_data)
|
|
{
|
|
GimpModuleDB *db = GIMP_MODULE_DB (user_data);
|
|
GimpModule *module;
|
|
gboolean load_inhibit;
|
|
|
|
if (! valid_module_name (file_data->filename))
|
|
return;
|
|
|
|
/* don't load if we already know about it */
|
|
if (gimp_module_db_module_find_by_path (db, file_data->filename))
|
|
return;
|
|
|
|
load_inhibit = is_in_inhibit_list (file_data->filename,
|
|
db->load_inhibit);
|
|
|
|
module = gimp_module_new (file_data->filename,
|
|
load_inhibit,
|
|
db->verbose);
|
|
|
|
g_signal_connect (module, "modified",
|
|
G_CALLBACK (gimp_module_db_module_modified),
|
|
db);
|
|
|
|
db->modules = g_list_append (db->modules, module);
|
|
g_signal_emit (db, db_signals[ADD], 0, module);
|
|
}
|
|
|
|
static GimpModule *
|
|
gimp_module_db_module_find_by_path (GimpModuleDB *db,
|
|
const char *fullpath)
|
|
{
|
|
GList *list;
|
|
|
|
for (list = db->modules; list; list = g_list_next (list))
|
|
{
|
|
GimpModule *module = list->data;
|
|
|
|
if (! strcmp (module->filename, fullpath))
|
|
return module;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef DUMP_DB
|
|
static void
|
|
gimp_module_db_dump_module (gpointer data,
|
|
gpointer user_data)
|
|
{
|
|
GimpModule *module = data;
|
|
|
|
g_print ("\n%s: %s\n",
|
|
gimp_filename_to_utf8 (module->filename),
|
|
gimp_module_state_name (module->state));
|
|
|
|
g_print (" module: %p lasterr: %s query: %p register: %p\n",
|
|
module->module,
|
|
module->last_module_error ? module->last_module_error : "NONE",
|
|
module->query_module,
|
|
module->register_module);
|
|
|
|
if (i->info)
|
|
{
|
|
g_print (" purpose: %s\n"
|
|
" author: %s\n"
|
|
" version: %s\n"
|
|
" copyright: %s\n"
|
|
" date: %s\n",
|
|
module->info->purpose ? module->info->purpose : "NONE",
|
|
module->info->author ? module->info->author : "NONE",
|
|
module->info->version ? module->info->version : "NONE",
|
|
module->info->copyright ? module->info->copyright : "NONE",
|
|
module->info->date ? module->info->date : "NONE");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
gimp_module_db_module_on_disk_func (gpointer data,
|
|
gpointer user_data)
|
|
{
|
|
GimpModule *module = data;
|
|
GList **kill_list = user_data;
|
|
gboolean old_on_disk;
|
|
|
|
old_on_disk = module->on_disk;
|
|
|
|
module->on_disk = g_file_test (module->filename, G_FILE_TEST_IS_REGULAR);
|
|
|
|
/* if it's not on the disk, and it isn't in memory, mark it to be
|
|
* removed later.
|
|
*/
|
|
if (! module->on_disk && ! module->module)
|
|
{
|
|
*kill_list = g_list_append (*kill_list, module);
|
|
module = NULL;
|
|
}
|
|
|
|
if (module && module->on_disk != old_on_disk)
|
|
gimp_module_modified (module);
|
|
}
|
|
|
|
static void
|
|
gimp_module_db_module_remove_func (gpointer data,
|
|
gpointer user_data)
|
|
{
|
|
GimpModule *module = data;
|
|
GimpModuleDB *db = user_data;
|
|
|
|
g_signal_handlers_disconnect_by_func (module,
|
|
gimp_module_db_module_modified,
|
|
db);
|
|
|
|
g_list_remove (db->modules, module);
|
|
g_signal_emit (db, db_signals[REMOVE], 0, module);
|
|
}
|
|
|
|
static void
|
|
gimp_module_db_module_modified (GimpModule *module,
|
|
GimpModuleDB *db)
|
|
{
|
|
g_signal_emit (db, db_signals[MODULE_MODIFIED], 0, module);
|
|
}
|