diff --git a/ChangeLog b/ChangeLog index ab91d42840..55ad13b41c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2001-10-18 Michael Natterer + + * app/Makefile.am + * app/module_db.[ch]: removed. + + * app/core/Makefile.am + * app/core/core-types.h + * app/core/gimpmoduleinfo.[ch] + * app/core/gimpmodules.[ch]: new files containing the module info + object and the module list handling code. + + * app/gui/Makefile.am + * app/gui/module-browser.[ch]: new files containing the GUI. + + * app/xcf/xcf.[ch]: pass a "Gimp" pointer to xcf_exit(). + + * app/core/gimp.[ch]: handle modules and xcf init/exit here too. + + * app/app_procs.c: don't touch the modules and xcf stuff any more. + + * app/gui/dialogs-constructors.c: changed accordingly. + 2001-10-18 Michael Natterer * app/core/gimpcontainer.[ch]: added properties for "children_type" diff --git a/app/Makefile.am b/app/Makefile.am index e73a8156a0..cd295c5eed 100644 --- a/app/Makefile.am +++ b/app/Makefile.am @@ -31,8 +31,6 @@ gimp_SOURCES = @STRIP_BEGIN@ \ ## image_map.c \ image_map.h \ - module_db.c \ - module_db.h \ user_install.c \ user_install.h \ ## @@ -130,10 +128,10 @@ gimp_LDADD = @STRIP_BEGIN@ \ tools/libapptools.a \ display/libappdisplay.a \ widgets/libappwidgets.a \ - xcf/libappxcf.a \ plug-in/libappplug-in.a \ pdb/libapppdb.a \ core/libappcore.a \ + xcf/libappxcf.a \ paint-funcs/libapppaint-funcs.a \ base/libappbase.a \ $(top_builddir)/libgimpcolor/libgimpcolor-$(LT_RELEASE).la \ diff --git a/app/app_procs.c b/app/app_procs.c index 526929a1c2..14f5d9dfb4 100644 --- a/app/app_procs.c +++ b/app/app_procs.c @@ -43,8 +43,6 @@ #include "pdb/internal_procs.h" -#include "xcf/xcf.h" - #include "display/gimpdisplay-foreach.h" #include "tools/tool_manager.h" @@ -60,7 +58,6 @@ #include "docindex.h" #include "errors.h" #include "gimprc.h" -#include "module_db.h" #include "plug_in.h" #include "undo.h" #include "user_install.h" @@ -99,7 +96,7 @@ app_init (gint gimp_argc, /* Create an instance of the "Gimp" object which is the root of the * core object system */ - the_gimp = gimp_new (); + the_gimp = gimp_new (be_verbose); /* Check if the user's gimp_directory exists */ @@ -162,10 +159,6 @@ app_init (gint gimp_argc, app_init_update_status (_("Procedural Database"), NULL, -1); internal_procs_init (the_gimp); - /* Initialize the xcf file format routines - */ - xcf_init (the_gimp); - /* Now we are ready to draw the splash-screen-image * to the start-up window */ @@ -179,7 +172,6 @@ app_init (gint gimp_argc, gimp_restore (the_gimp, no_data); plug_in_init (); /* initialize the plug in structures */ - module_db_init (); /* load any modules we need */ if (! no_interface) { @@ -241,7 +233,6 @@ app_exit_finish (void) gui_shutdown (the_gimp); } - module_db_free (); plug_in_kill (); tool_manager_exit (the_gimp); @@ -251,8 +242,6 @@ app_exit_finish (void) gui_exit (the_gimp); } - xcf_exit (); - gimp_shutdown (the_gimp); g_object_unref (G_OBJECT (the_gimp)); diff --git a/app/core/Makefile.am b/app/core/Makefile.am index 32d05198cb..ed37803744 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -89,6 +89,10 @@ libappcore_a_sources = @STRIP_BEGIN@ \ gimplayermask.h \ gimplist.c \ gimplist.h \ + gimpmoduleinfo.c \ + gimpmoduleinfo.h \ + gimpmodules.c \ + gimpmodules.h \ gimpobject.c \ gimpobject.h \ gimppattern.c \ diff --git a/app/core/core-types.h b/app/core/core-types.h index 296691819e..863a148063 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -165,6 +165,8 @@ typedef struct _Gimp Gimp; typedef struct _GimpParasiteList GimpParasiteList; +typedef struct _GimpModuleInfoObj GimpModuleInfoObj; + typedef struct _GimpContainer GimpContainer; typedef struct _GimpList GimpList; typedef struct _GimpDataList GimpDataList; diff --git a/app/core/gimp-modules.c b/app/core/gimp-modules.c new file mode 100644 index 0000000000..33eb5a35c7 --- /dev/null +++ b/app/core/gimp-modules.c @@ -0,0 +1,400 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmodules.c + * (C) 1999 Austin Donnelly + * + * 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 +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include + +#include "libgimpbase/gimpbase.h" + +#include "core-types.h" + +#include "core/gimp.h" +#include "core/gimpcoreconfig.h" +#include "core/gimpdatafiles.h" +#include "core/gimplist.h" +#include "core/gimpmoduleinfo.h" +#include "core/gimpmodules.h" + +#include "gimprc.h" + +#include "libgimp/gimpintl.h" + + +static void gimp_modules_module_initialize (const gchar *filename, + gpointer loader_data); + +static GimpModuleInfoObj * gimp_modules_module_find_by_path (Gimp *gimp, + const char *fullpath); + +#ifdef DUMP_DB +static void print_module_info (gpointer data, + gpointer user_data); +#endif + +static gboolean gimp_modules_write_modulerc (Gimp *gimp); + +static void gimp_modules_module_free_func (gpointer data, + gpointer user_data); +static void gimp_modules_module_on_disk_func (gpointer data, + gpointer user_data); +static void gimp_modules_module_remove_func (gpointer data, + gpointer user_data); + + +void +gimp_modules_init (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + gimp->modules = gimp_list_new (GIMP_TYPE_MODULE_INFO, + GIMP_CONTAINER_POLICY_STRONG); + gimp->write_modulerc = FALSE; +} + +void +gimp_modules_exit (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + if (gimp->modules) + { + g_object_unref (G_OBJECT (gimp->modules)); + gimp->modules = NULL; + } +} + +void +gimp_modules_load (Gimp *gimp) +{ + gchar *filename; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + filename = gimp_personal_rc_file ("modulerc"); + gimprc_parse_file (filename); + g_free (filename); + + if (g_module_supported ()) + gimp_datafiles_read_directories (gimp->config->module_path, + 0 /* no flags */, + gimp_modules_module_initialize, + gimp); + +#ifdef DUMP_DB + gimp_container_foreach (modules, print_module_info, NULL); +#endif +} + +void +gimp_modules_unload (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + if (gimp->write_modulerc) + { + if (gimp_modules_write_modulerc (gimp)) + { + gimp->write_modulerc = FALSE; + } + } + + gimp_container_foreach (gimp->modules, gimp_modules_module_free_func, NULL); +} + +void +gimp_modules_refresh (Gimp *gimp) +{ + GList *kill_list = NULL; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + /* remove modules we don't have on disk anymore */ + gimp_container_foreach (gimp->modules, + gimp_modules_module_on_disk_func, + &kill_list); + g_list_foreach (kill_list, + gimp_modules_module_remove_func, + gimp); + g_list_free (kill_list); + + /* walk filesystem and add new things we find */ + gimp_datafiles_read_directories (gimp->config->module_path, + 0 /* no flags */, + gimp_modules_module_initialize, + gimp); +} + +static void +gimp_modules_module_free_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info = data; + + if (module_info->module && + module_info->unload && + module_info->state == GIMP_MODULE_STATE_LOADED_OK) + { + gimp_module_info_module_unload (module_info, FALSE); + } +} + +static void +add_to_inhibit_string (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info = data; + GString *str = user_data; + + if (module_info->load_inhibit) + { + str = g_string_append_c (str, G_SEARCHPATH_SEPARATOR); + str = g_string_append (str, module_info->fullpath); + } +} + +static gboolean +gimp_modules_write_modulerc (Gimp *gimp) +{ + GString *str; + gchar *p; + gchar *filename; + FILE *fp; + gboolean saved = FALSE; + + str = g_string_new (NULL); + gimp_container_foreach (gimp->modules, add_to_inhibit_string, str); + if (str->len > 0) + p = str->str + 1; + else + p = ""; + + filename = gimp_personal_rc_file ("modulerc"); + fp = fopen (filename, "wt"); + g_free (filename); + if (fp) + { + fprintf (fp, "(module-load-inhibit \"%s\")\n", p); + fclose (fp); + saved = TRUE; + } + + g_string_free (str, TRUE); + + return saved; +} + +/* name must be of the form lib*.so (Unix) or *.dll (Win32) */ +static gboolean +valid_module_name (const gchar *filename) +{ + gchar *basename; + gint len; + + basename = g_path_get_basename (filename); + + len = strlen (basename); + +#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) && !defined(__EMX__) + if (len < 3 + 1 + 3) + goto no_module; + + if (strncmp (basename, "lib", 3)) + goto no_module; + + if (strcmp (basename + len - 3, ".so")) + goto no_module; +#else + if (len < 1 + 4) + goto no_module; + + if (g_strcasecmp (basename + len - 4, ".dll")) + goto no_module; +#endif + + g_free (basename); + + return TRUE; + + no_module: + g_free (basename); + + return FALSE; +} + +static void +gimp_modules_module_initialize (const gchar *filename, + gpointer loader_data) +{ + GimpModuleInfoObj *module_info; + Gimp *gimp; + + gimp = GIMP (loader_data); + + if (! valid_module_name (filename)) + return; + + /* don't load if we already know about it */ + if (gimp_modules_module_find_by_path (gimp, filename)) + return; + + module_info = gimp_module_info_new (filename); + + gimp_module_info_set_load_inhibit (module_info, + gimp->config->module_db_load_inhibit); + + if (! module_info->load_inhibit) + { + if (gimp->be_verbose) + g_print (_("load module: \"%s\"\n"), filename); + + gimp_module_info_module_load (module_info, TRUE); + } + else + { + if (gimp->be_verbose) + g_print (_("skipping module: \"%s\"\n"), filename); + + module_info->state = GIMP_MODULE_STATE_UNLOADED_OK; + } + + gimp_container_add (gimp->modules, GIMP_OBJECT (module_info)); + + g_object_unref (G_OBJECT (module_info)); +} + +typedef struct +{ + const gchar *search_key; + GimpModuleInfoObj *found; +} find_by_path_closure; + +static void +gimp_modules_module_path_cmp_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + find_by_path_closure *closure; + + module_info = (GimpModuleInfoObj *) data; + closure = (find_by_path_closure *) user_data; + + if (! strcmp (module_info->fullpath, closure->search_key)) + closure->found = module_info; +} + +static GimpModuleInfoObj * +gimp_modules_module_find_by_path (Gimp *gimp, + const char *fullpath) +{ + find_by_path_closure cl; + + cl.found = NULL; + cl.search_key = fullpath; + + gimp_container_foreach (gimp->modules, + gimp_modules_module_path_cmp_func, &cl); + + return cl.found; +} + +#ifdef DUMP_DB +static void +print_module_info (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *i = data; + + g_print ("\n%s: %s\n", + i->fullpath, statename[i->state]); + g_print (" module:%p lasterr:%s init:%p unload:%p\n", + i->module, i->last_module_error? i->last_module_error : "NONE", + i->init, i->unload); + if (i->info) + { + g_print (" shutdown_data: %p\n" + " purpose: %s\n" + " author: %s\n" + " version: %s\n" + " copyright: %s\n" + " date: %s\n", + i->info->shutdown_data, + i->info->purpose, i->info->author, i->info->version, + i->info->copyright, i->info->date); + } +} +#endif + +static void +gimp_modules_module_on_disk_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + GList **kill_list; + gint old_on_disk; + struct stat statbuf; + gint ret; + + module_info = (GimpModuleInfoObj *) data; + kill_list = (GList **) user_data; + + old_on_disk = module_info->on_disk; + + ret = stat (module_info->fullpath, &statbuf); + if (ret != 0) + module_info->on_disk = FALSE; + else + module_info->on_disk = TRUE; + + /* if it's not on the disk, and it isn't in memory, mark it to be + * removed later. + */ + if (! module_info->on_disk && ! module_info->module) + { + *kill_list = g_list_append (*kill_list, module_info); + module_info = NULL; + } + + if (module_info && module_info->on_disk != old_on_disk) + gimp_module_info_modified (module_info); +} + +static void +gimp_modules_module_remove_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + Gimp *gimp; + + module_info = (GimpModuleInfoObj *) data; + gimp = (Gimp *) user_data; + + gimp_container_remove (gimp->modules, GIMP_OBJECT (module_info)); +} diff --git a/app/module_db.h b/app/core/gimp-modules.h similarity index 69% rename from app/module_db.h rename to app/core/gimp-modules.h index fa1ecc49e2..48aa49e665 100644 --- a/app/module_db.h +++ b/app/core/gimp-modules.h @@ -1,7 +1,8 @@ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * - * module_db.h (C) 1999 Austin Donnelly + * gimpmodules.h + * (C) 1999 Austin Donnelly * * 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 @@ -18,16 +19,17 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __MODULE_DB_H__ +#ifndef __GIMP_MODULES_H__ +#define __GIMP_MODULES_H__ -/* Load any modules we find on the module-path set in the gimprc */ -void module_db_init (void); +void gimp_modules_init (Gimp *gimp); +void gimp_modules_exit (Gimp *gimp); -/* Unload all modules, in case a module needs some cleanups */ -void module_db_free (void); +void gimp_modules_load (Gimp *gimp); +void gimp_modules_unload (Gimp *gimp); -GtkWidget * module_db_browser_new (void); +void gimp_modules_refresh (Gimp *gimp); -#endif /* __MODULE_DB_H__ */ +#endif /* __GIMP_MODULES_H__ */ diff --git a/app/core/gimp.c b/app/core/gimp.c index 398c2b8a3c..e27ae57e04 100644 --- a/app/core/gimp.c +++ b/app/core/gimp.c @@ -31,6 +31,8 @@ #include "pdb/procedural_db.h" +#include "xcf/xcf.h" + #include "gimp.h" #include "gimpbrush.h" #include "gimpbrushgenerated.h" @@ -45,6 +47,7 @@ #include "gimpimage-new.h" #include "gimpimagefile.h" #include "gimplist.h" +#include "gimpmodules.h" #include "gimppalette.h" #include "gimppattern.h" #include "gimpparasite.h" @@ -115,6 +118,8 @@ gimp_init (Gimp *gimp) { gimp_core_config_init (gimp); + gimp->be_verbose = FALSE; + gimp->create_display_func = NULL; gimp->gui_set_busy_func = NULL; gimp->gui_unset_busy_func = NULL; @@ -126,6 +131,8 @@ gimp_init (Gimp *gimp) gimp_parasites_init (gimp); + gimp_modules_init (gimp); + gimp->images = gimp_list_new (GIMP_TYPE_IMAGE, GIMP_CONTAINER_POLICY_WEAK); gimp->next_image_ID = 1; @@ -145,6 +152,8 @@ gimp_init (Gimp *gimp) procedural_db_init (gimp); + xcf_init (gimp); + gimp->tool_info_list = gimp_list_new (GIMP_TYPE_TOOL_INFO, GIMP_CONTAINER_POLICY_STRONG); gimp->standard_tool_info = NULL; @@ -220,6 +229,8 @@ gimp_finalize (GObject *object) gimp->tool_info_list = NULL; } + xcf_exit (gimp); + if (gimp->procedural_ht) procedural_db_free (gimp); @@ -277,6 +288,9 @@ gimp_finalize (GObject *object) gimp->images = NULL; } + if (gimp->modules) + gimp_modules_exit (gimp); + if (gimp->parasites) gimp_parasites_exit (gimp); @@ -287,12 +301,14 @@ gimp_finalize (GObject *object) } Gimp * -gimp_new (void) +gimp_new (gboolean be_verbose) { Gimp *gimp; gimp = g_object_new (GIMP_TYPE_GIMP, NULL); + gimp->be_verbose = be_verbose ? TRUE : FALSE; + return gimp; } @@ -412,6 +428,8 @@ gimp_restore (Gimp *gimp, gimp_documents_load (gimp); app_init_update_status (NULL, NULL, 1.00); + + gimp_modules_load (gimp); } void @@ -419,6 +437,7 @@ gimp_shutdown (Gimp *gimp) { g_return_if_fail (GIMP_IS_GIMP (gimp)); + gimp_modules_unload (gimp); gimp_data_factory_data_save (gimp->brush_factory); gimp_data_factory_data_save (gimp->pattern_factory); gimp_data_factory_data_save (gimp->gradient_factory); diff --git a/app/core/gimp.h b/app/core/gimp.h index 4135dfa91e..bbc1140ddf 100644 --- a/app/core/gimp.h +++ b/app/core/gimp.h @@ -44,6 +44,8 @@ struct _Gimp GimpCoreConfig *config; + gboolean be_verbose; + GimpCreateDisplayFunc create_display_func; GimpSetBusyFunc gui_set_busy_func; GimpUnsetBusyFunc gui_unset_busy_func; @@ -56,6 +58,9 @@ struct _Gimp GimpParasiteList *parasites; + GimpContainer *modules; + gboolean write_modulerc; + GimpContainer *images; gint next_image_ID; guint32 next_guide_ID; @@ -110,7 +115,7 @@ struct _GimpClass GType gimp_get_type (void); -Gimp * gimp_new (void); +Gimp * gimp_new (gboolean be_verbose); void gimp_initialize (Gimp *gimp); diff --git a/app/core/gimpmoduleinfo.c b/app/core/gimpmoduleinfo.c new file mode 100644 index 0000000000..3ee46f4126 --- /dev/null +++ b/app/core/gimpmoduleinfo.c @@ -0,0 +1,400 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmoduleinfo.c + * (C) 1999 Austin Donnelly + * + * 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 + +#include + +#include "libgimp/gimpmodule.h" + +#include "core-types.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 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; + + object_class = G_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, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->finalize = gimp_module_info_finalize; + + 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); +} + +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_warning (_("module load error: %s: %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_warning ("%s: module_init() symbol not found", + module_info->fullpath); + + 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; + } +} diff --git a/app/core/gimpmoduleinfo.h b/app/core/gimpmoduleinfo.h new file mode 100644 index 0000000000..fab3884f53 --- /dev/null +++ b/app/core/gimpmoduleinfo.h @@ -0,0 +1,102 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmoduleinfo.h + * (C) 1999 Austin Donnelly + * + * 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. + */ + +#ifndef __GIMP_MODULE_INFO_H__ +#define __GIMP_MODULE_INFO_H__ + + +#include "libgimp/gimpmodule.h" + +#include "gimpobject.h" + + +typedef enum +{ + GIMP_MODULE_STATE_ERROR, /* missing module_load function or other error */ + GIMP_MODULE_STATE_LOADED_OK, /* happy and running (normal state of affairs) */ + GIMP_MODULE_STATE_LOAD_FAILED, /* module_load returned GIMP_MODULE_UNLOAD */ + GIMP_MODULE_STATE_UNLOAD_REQUESTED, /* sent unload request, waiting for callback */ + GIMP_MODULE_STATE_UNLOADED_OK /* callback arrived, module not in memory anymore */ +} GimpModuleState; + + +#define GIMP_TYPE_MODULE_INFO (gimp_module_info_get_type ()) +#define GIMP_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObj)) +#define GIMP_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) +#define GIMP_IS_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_MODULE_INFO)) +#define GIMP_IS_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MODULE_INFO)) +#define GIMP_MODULE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) + + +typedef struct _GimpModuleInfoObjClass GimpModuleInfoObjClass; + +struct _GimpModuleInfoObj +{ + GimpObject parent_instance; + + gchar *fullpath; /* path to the module */ + GimpModuleState state; /* what's happened to the module */ + gboolean on_disk; /* TRUE if file still exists */ + gboolean load_inhibit; /* user requests not to load at boot time */ + + /* Count of times main gimp is within the module. Normally, this + * will be 1, and we assume that the module won't call its + * unload callback until it is satisfied that it's not in use any + * more. refs can be 2 temporarily while we're running the module's + * unload function, to stop the module attempting to unload + * itself. + */ + gint refs; + + /* stuff from now on may be NULL depending on the state the module is in */ + GimpModuleInfo *info; /* returned values from module_init */ + GModule *module; /* handle on the module */ + gchar *last_module_error; + + GimpModuleInitFunc init; + GimpModuleUnloadFunc unload; +}; + +struct _GimpModuleInfoObjClass +{ + GimpObjectClass parent_class; + + void (* modified) (GimpModuleInfoObj *module_info); +}; + + +GType gimp_module_info_get_type (void); + +GimpModuleInfoObj * gimp_module_info_new (const gchar *filename); + +void gimp_module_info_modified (GimpModuleInfoObj *module); +void gimp_module_info_set_load_inhibit (GimpModuleInfoObj *module, + const gchar *inhibit_list); + +void gimp_module_info_module_load (GimpModuleInfoObj *module_info, + gboolean verbose); +void gimp_module_info_module_unload (GimpModuleInfoObj *module_info, + gboolean verbose); +void gimp_module_info_module_ref (GimpModuleInfoObj *module_info); +void gimp_module_info_module_unref (GimpModuleInfoObj *module_info); + + +#endif /* __GIMP_MODULE_INFO_H__ */ diff --git a/app/core/gimpmodules.c b/app/core/gimpmodules.c new file mode 100644 index 0000000000..33eb5a35c7 --- /dev/null +++ b/app/core/gimpmodules.c @@ -0,0 +1,400 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmodules.c + * (C) 1999 Austin Donnelly + * + * 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 +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include + +#include "libgimpbase/gimpbase.h" + +#include "core-types.h" + +#include "core/gimp.h" +#include "core/gimpcoreconfig.h" +#include "core/gimpdatafiles.h" +#include "core/gimplist.h" +#include "core/gimpmoduleinfo.h" +#include "core/gimpmodules.h" + +#include "gimprc.h" + +#include "libgimp/gimpintl.h" + + +static void gimp_modules_module_initialize (const gchar *filename, + gpointer loader_data); + +static GimpModuleInfoObj * gimp_modules_module_find_by_path (Gimp *gimp, + const char *fullpath); + +#ifdef DUMP_DB +static void print_module_info (gpointer data, + gpointer user_data); +#endif + +static gboolean gimp_modules_write_modulerc (Gimp *gimp); + +static void gimp_modules_module_free_func (gpointer data, + gpointer user_data); +static void gimp_modules_module_on_disk_func (gpointer data, + gpointer user_data); +static void gimp_modules_module_remove_func (gpointer data, + gpointer user_data); + + +void +gimp_modules_init (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + gimp->modules = gimp_list_new (GIMP_TYPE_MODULE_INFO, + GIMP_CONTAINER_POLICY_STRONG); + gimp->write_modulerc = FALSE; +} + +void +gimp_modules_exit (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + if (gimp->modules) + { + g_object_unref (G_OBJECT (gimp->modules)); + gimp->modules = NULL; + } +} + +void +gimp_modules_load (Gimp *gimp) +{ + gchar *filename; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + filename = gimp_personal_rc_file ("modulerc"); + gimprc_parse_file (filename); + g_free (filename); + + if (g_module_supported ()) + gimp_datafiles_read_directories (gimp->config->module_path, + 0 /* no flags */, + gimp_modules_module_initialize, + gimp); + +#ifdef DUMP_DB + gimp_container_foreach (modules, print_module_info, NULL); +#endif +} + +void +gimp_modules_unload (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + if (gimp->write_modulerc) + { + if (gimp_modules_write_modulerc (gimp)) + { + gimp->write_modulerc = FALSE; + } + } + + gimp_container_foreach (gimp->modules, gimp_modules_module_free_func, NULL); +} + +void +gimp_modules_refresh (Gimp *gimp) +{ + GList *kill_list = NULL; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + /* remove modules we don't have on disk anymore */ + gimp_container_foreach (gimp->modules, + gimp_modules_module_on_disk_func, + &kill_list); + g_list_foreach (kill_list, + gimp_modules_module_remove_func, + gimp); + g_list_free (kill_list); + + /* walk filesystem and add new things we find */ + gimp_datafiles_read_directories (gimp->config->module_path, + 0 /* no flags */, + gimp_modules_module_initialize, + gimp); +} + +static void +gimp_modules_module_free_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info = data; + + if (module_info->module && + module_info->unload && + module_info->state == GIMP_MODULE_STATE_LOADED_OK) + { + gimp_module_info_module_unload (module_info, FALSE); + } +} + +static void +add_to_inhibit_string (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info = data; + GString *str = user_data; + + if (module_info->load_inhibit) + { + str = g_string_append_c (str, G_SEARCHPATH_SEPARATOR); + str = g_string_append (str, module_info->fullpath); + } +} + +static gboolean +gimp_modules_write_modulerc (Gimp *gimp) +{ + GString *str; + gchar *p; + gchar *filename; + FILE *fp; + gboolean saved = FALSE; + + str = g_string_new (NULL); + gimp_container_foreach (gimp->modules, add_to_inhibit_string, str); + if (str->len > 0) + p = str->str + 1; + else + p = ""; + + filename = gimp_personal_rc_file ("modulerc"); + fp = fopen (filename, "wt"); + g_free (filename); + if (fp) + { + fprintf (fp, "(module-load-inhibit \"%s\")\n", p); + fclose (fp); + saved = TRUE; + } + + g_string_free (str, TRUE); + + return saved; +} + +/* name must be of the form lib*.so (Unix) or *.dll (Win32) */ +static gboolean +valid_module_name (const gchar *filename) +{ + gchar *basename; + gint len; + + basename = g_path_get_basename (filename); + + len = strlen (basename); + +#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) && !defined(__EMX__) + if (len < 3 + 1 + 3) + goto no_module; + + if (strncmp (basename, "lib", 3)) + goto no_module; + + if (strcmp (basename + len - 3, ".so")) + goto no_module; +#else + if (len < 1 + 4) + goto no_module; + + if (g_strcasecmp (basename + len - 4, ".dll")) + goto no_module; +#endif + + g_free (basename); + + return TRUE; + + no_module: + g_free (basename); + + return FALSE; +} + +static void +gimp_modules_module_initialize (const gchar *filename, + gpointer loader_data) +{ + GimpModuleInfoObj *module_info; + Gimp *gimp; + + gimp = GIMP (loader_data); + + if (! valid_module_name (filename)) + return; + + /* don't load if we already know about it */ + if (gimp_modules_module_find_by_path (gimp, filename)) + return; + + module_info = gimp_module_info_new (filename); + + gimp_module_info_set_load_inhibit (module_info, + gimp->config->module_db_load_inhibit); + + if (! module_info->load_inhibit) + { + if (gimp->be_verbose) + g_print (_("load module: \"%s\"\n"), filename); + + gimp_module_info_module_load (module_info, TRUE); + } + else + { + if (gimp->be_verbose) + g_print (_("skipping module: \"%s\"\n"), filename); + + module_info->state = GIMP_MODULE_STATE_UNLOADED_OK; + } + + gimp_container_add (gimp->modules, GIMP_OBJECT (module_info)); + + g_object_unref (G_OBJECT (module_info)); +} + +typedef struct +{ + const gchar *search_key; + GimpModuleInfoObj *found; +} find_by_path_closure; + +static void +gimp_modules_module_path_cmp_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + find_by_path_closure *closure; + + module_info = (GimpModuleInfoObj *) data; + closure = (find_by_path_closure *) user_data; + + if (! strcmp (module_info->fullpath, closure->search_key)) + closure->found = module_info; +} + +static GimpModuleInfoObj * +gimp_modules_module_find_by_path (Gimp *gimp, + const char *fullpath) +{ + find_by_path_closure cl; + + cl.found = NULL; + cl.search_key = fullpath; + + gimp_container_foreach (gimp->modules, + gimp_modules_module_path_cmp_func, &cl); + + return cl.found; +} + +#ifdef DUMP_DB +static void +print_module_info (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *i = data; + + g_print ("\n%s: %s\n", + i->fullpath, statename[i->state]); + g_print (" module:%p lasterr:%s init:%p unload:%p\n", + i->module, i->last_module_error? i->last_module_error : "NONE", + i->init, i->unload); + if (i->info) + { + g_print (" shutdown_data: %p\n" + " purpose: %s\n" + " author: %s\n" + " version: %s\n" + " copyright: %s\n" + " date: %s\n", + i->info->shutdown_data, + i->info->purpose, i->info->author, i->info->version, + i->info->copyright, i->info->date); + } +} +#endif + +static void +gimp_modules_module_on_disk_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + GList **kill_list; + gint old_on_disk; + struct stat statbuf; + gint ret; + + module_info = (GimpModuleInfoObj *) data; + kill_list = (GList **) user_data; + + old_on_disk = module_info->on_disk; + + ret = stat (module_info->fullpath, &statbuf); + if (ret != 0) + module_info->on_disk = FALSE; + else + module_info->on_disk = TRUE; + + /* if it's not on the disk, and it isn't in memory, mark it to be + * removed later. + */ + if (! module_info->on_disk && ! module_info->module) + { + *kill_list = g_list_append (*kill_list, module_info); + module_info = NULL; + } + + if (module_info && module_info->on_disk != old_on_disk) + gimp_module_info_modified (module_info); +} + +static void +gimp_modules_module_remove_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + Gimp *gimp; + + module_info = (GimpModuleInfoObj *) data; + gimp = (Gimp *) user_data; + + gimp_container_remove (gimp->modules, GIMP_OBJECT (module_info)); +} diff --git a/app/core/gimpmodules.h b/app/core/gimpmodules.h new file mode 100644 index 0000000000..48aa49e665 --- /dev/null +++ b/app/core/gimpmodules.h @@ -0,0 +1,35 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmodules.h + * (C) 1999 Austin Donnelly + * + * 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. + */ + +#ifndef __GIMP_MODULES_H__ +#define __GIMP_MODULES_H__ + + +void gimp_modules_init (Gimp *gimp); +void gimp_modules_exit (Gimp *gimp); + +void gimp_modules_load (Gimp *gimp); +void gimp_modules_unload (Gimp *gimp); + +void gimp_modules_refresh (Gimp *gimp); + + +#endif /* __GIMP_MODULES_H__ */ diff --git a/app/dialogs/dialogs-constructors.c b/app/dialogs/dialogs-constructors.c index d612d974ab..3450adf995 100644 --- a/app/dialogs/dialogs-constructors.c +++ b/app/dialogs/dialogs-constructors.c @@ -64,6 +64,7 @@ #include "gradients-commands.h" #include "layers-commands.h" #include "menus.h" +#include "module-browser.h" #include "palette-editor.h" #include "palette-select.h" #include "palettes-commands.h" @@ -79,7 +80,6 @@ #include "devices.h" #include "docindex.h" #include "gimprc.h" -#include "module_db.h" #include "undo_history.h" #ifdef DISPLAY_FILTERS @@ -230,7 +230,7 @@ GtkWidget * dialogs_module_browser_get (GimpDialogFactory *factory, GimpContext *context) { - return module_db_browser_new (); + return module_browser_new (); } GtkWidget * diff --git a/app/dialogs/module-dialog.c b/app/dialogs/module-dialog.c index 77f4ee98c7..d6ad2156a1 100644 --- a/app/dialogs/module-dialog.c +++ b/app/dialogs/module-dialog.c @@ -1,7 +1,8 @@ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * - * module_db.c (C) 1999 Austin Donnelly + * module-browser.c + * (C) 1999 Austin Donnelly * * 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 @@ -20,421 +21,78 @@ #include "config.h" -#include - -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - #include -#include "libgimpbase/gimpbase.h" #include "libgimpwidgets/gimpwidgets.h" -#include "core/core-types.h" +#include "gui-types.h" #include "core/gimp.h" -#include "core/gimpcoreconfig.h" -#include "core/gimpdatafiles.h" -#include "core/gimplist.h" +#include "core/gimpcontainer.h" +#include "core/gimpmoduleinfo.h" +#include "core/gimpmodules.h" + +#include "module-browser.h" #include "app_procs.h" -#include "appenv.h" -#include "module_db.h" -#include "gimprc.h" - -#include "libgimp/gimpmodule.h" #include "libgimp/gimpintl.h" -/* debug control: */ - -/*#define DUMP_DB*/ -/*#define DEBUG*/ - -#ifdef DEBUG -#undef DUMP_DB -#define DUMP_DB -#define TRC(x) printf x -#else -#define TRC(x) -#endif - - -typedef enum -{ - ST_MODULE_ERROR, /* missing module_load function or other error */ - ST_LOADED_OK, /* happy and running (normal state of affairs) */ - ST_LOAD_FAILED, /* module_load returned GIMP_MODULE_UNLOAD */ - ST_UNLOAD_REQUESTED, /* sent unload request, waiting for callback */ - ST_UNLOADED_OK /* callback arrived, module not in memory anymore */ -} module_state; - -enum -{ - MODIFIED, - LAST_SIGNAL -}; - - -#define GIMP_TYPE_MODULE_INFO (gimp_module_info_get_type ()) -#define GIMP_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObj)) -#define GIMP_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) -#define GIMP_IS_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_MODULE_INFO)) -#define GIMP_IS_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MODULE_INFO)) -#define GIMP_MODULE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) - - -typedef struct _GimpModuleInfoObj GimpModuleInfoObj; -typedef struct _GimpModuleInfoObjClass GimpModuleInfoObjClass; - -struct _GimpModuleInfoObj -{ - GimpObject parent_instance; - - gchar *fullpath; /* path to the module */ - module_state state; /* what's happened to the module */ - gboolean ondisk; /* TRUE if file still exists */ - gboolean load_inhibit; /* user requests not to load at boot time */ - gint refs; /* how many time we're running in the module */ - - /* stuff from now on may be NULL depending on the state the module is in */ - GimpModuleInfo *info; /* returned values from module_init */ - GModule *module; /* handle on the module */ - gchar *last_module_error; - - GimpModuleInitFunc init; - GimpModuleUnloadFunc unload; -}; - -struct _GimpModuleInfoObjClass -{ - GimpObjectClass parent_class; - - void (* modified) (GimpModuleInfoObj *module_info); -}; - - -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 guint module_info_signals[LAST_SIGNAL]; - -static GimpObjectClass *parent_class = NULL; - - -static 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; - - object_class = G_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, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - object_class->finalize = gimp_module_info_finalize; - - klass->modified = NULL; -} - -static void -gimp_module_info_init (GimpModuleInfoObj *mod) -{ - /* don't need to do anything */ -} - -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); -} - -/* exported API: */ - -static void -gimp_module_info_modified (GimpModuleInfoObj *mod) -{ - g_signal_emit (G_OBJECT (mod), module_info_signals[MODIFIED], 0); -} - -static GimpModuleInfoObj * -gimp_module_info_new (void) -{ - return GIMP_MODULE_INFO (g_object_new (GIMP_TYPE_MODULE_INFO, NULL)); -} - - -/* dialog stuff */ - -static const gchar * const statename[] = -{ - N_("Module error"), - N_("Loaded OK"), - N_("Load failed"), - N_("Unload requested"), - N_("Unloaded OK") -}; - -#ifdef __EMX__ -extern void gimp_color_selector_register (); -extern void gimp_color_selector_unregister (); -extern void dialog_register (); -extern void dialog_unregister (); - -static struct main_funcs_struc -{ - gchar *name; - void (*func) (); -} - -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 - - #define NUM_INFO_LINES 7 typedef struct { - GtkWidget *table; - GtkWidget *label[NUM_INFO_LINES]; - GtkWidget *button_label; + GtkWidget *table; + GtkWidget *label[NUM_INFO_LINES]; + GtkWidget *button_label; GimpModuleInfoObj *last_update; - GtkWidget *button; - GtkWidget *list; - GtkWidget *load_inhibit_check; + GtkWidget *button; + GtkWidget *list; + GtkWidget *load_inhibit_check; + + GQuark modules_handler_id; } BrowserState; -/* prototypes */ -static void module_initialize (const gchar *filename, - gpointer loader_data); -static void mod_load (GimpModuleInfoObj *mod, - gboolean verbose); -static void mod_unload (GimpModuleInfoObj *mod, - gboolean verbose); -static gboolean mod_idle_unref (GimpModuleInfoObj *mod); -static GimpModuleInfoObj * module_find_by_path (const gchar *fullpath); +/* local function prototypes */ -#ifdef DUMP_DB -static void print_module_info (gpointer data, - gpointer user_data); -#endif - -static void browser_popdown_callback (GtkWidget *widget, - gpointer data); -static void browser_destroy_callback (GtkWidget *widget, - gpointer data); -static void browser_info_update (GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_add (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_remove (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_init (BrowserState *st, - GtkWidget *table); -static void browser_select_callback (GtkWidget *widget, - GtkWidget *child); -static void browser_load_unload_callback (GtkWidget *widget, - gpointer data); -static void browser_refresh_callback (GtkWidget *widget, - gpointer data); -static void make_list_item (gpointer data, - gpointer user_data); - -static void gimp_module_ref (GimpModuleInfoObj *mod); -static void gimp_module_unref (GimpModuleInfoObj *mod); +static void browser_popdown_callback (GtkWidget *widget, + gpointer data); +static void browser_destroy_callback (GtkWidget *widget, + gpointer data); +static void browser_load_inhibit_callback (GtkWidget *widget, + gpointer data); +static void browser_select_callback (GtkWidget *widget, + GtkWidget *child); +static void browser_load_unload_callback (GtkWidget *widget, + gpointer data); +static void browser_refresh_callback (GtkWidget *widget, + gpointer data); +static void make_list_item (gpointer data, + gpointer user_data); +static void browser_info_add (GimpContainer *container, + GimpModuleInfoObj *mod, + BrowserState *st); +static void browser_info_remove (GimpContainer *container, + GimpModuleInfoObj *mod, + BrowserState *st); +static void browser_info_update (GimpModuleInfoObj *mod, + BrowserState *st); +static void browser_info_init (BrowserState *st, + GtkWidget *table); - -/* global set of module_info pointers */ -static GimpContainer *modules; -static GQuark modules_handler_id; - -/* If the inhibit state of any modules changes, we might need to - * re-write the modulerc. - */ -static gboolean need_to_rewrite_modulerc = FALSE; - - -/**************************************************************/ -/* Exported functions */ - -void -module_db_init (void) -{ - gchar *filename; - - /* load the modulerc file */ - filename = gimp_personal_rc_file ("modulerc"); - gimprc_parse_file (filename); - g_free (filename); - - /* Load and initialize gimp modules */ - - modules = gimp_list_new (GIMP_TYPE_MODULE_INFO, GIMP_CONTAINER_POLICY_WEAK); - - if (g_module_supported ()) - gimp_datafiles_read_directories (the_gimp->config->module_path, 0 /* no flags */, - module_initialize, NULL); -#ifdef DUMP_DB - gimp_container_foreach (modules, print_module_info, NULL); -#endif -} - -static void -free_a_single_module (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - - if (mod->module && mod->unload && mod->state == ST_LOADED_OK) - { - mod_unload (mod, FALSE); - } -} - -static void -add_to_inhibit_string (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - GString *str = user_data; - - if (mod->load_inhibit) - { - str = g_string_append_c (str, G_SEARCHPATH_SEPARATOR); - str = g_string_append (str, mod->fullpath); - } -} - - -static gboolean -module_db_write_modulerc (void) -{ - GString *str; - gchar *p; - gchar *filename; - FILE *fp; - gboolean saved = FALSE; - - str = g_string_new (NULL); - gimp_container_foreach (modules, add_to_inhibit_string, str); - if (str->len > 0) - p = str->str + 1; - else - p = ""; - - filename = gimp_personal_rc_file ("modulerc"); - fp = fopen (filename, "wt"); - g_free (filename); - if (fp) - { - fprintf (fp, "(module-load-inhibit \"%s\")\n", p); - fclose (fp); - saved = TRUE; - } - - g_string_free (str, TRUE); - return (saved); -} - - -void -module_db_free (void) -{ - if (need_to_rewrite_modulerc) - { - if (module_db_write_modulerc ()) - { - need_to_rewrite_modulerc = FALSE; - } - } - gimp_container_foreach (modules, free_a_single_module, NULL); -} - +/* public functions */ GtkWidget * -module_db_browser_new (void) +module_browser_new (void) { - GtkWidget *shell; - GtkWidget *hbox; - GtkWidget *vbox; - GtkWidget *listbox; - GtkWidget *button; + GtkWidget *shell; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *listbox; + GtkWidget *button; BrowserState *st; shell = gimp_dialog_new (_("Module DB"), "module_db_dialog", @@ -468,7 +126,7 @@ module_db_browser_new (void) gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), st->list); - gimp_container_foreach (modules, make_list_item, st); + gimp_container_foreach (the_gimp->modules, make_list_item, st); gtk_widget_show (st->list); @@ -507,14 +165,14 @@ module_db_browser_new (void) /* hook the GimpContainer signals so we can refresh the display * appropriately. */ - modules_handler_id = - gimp_container_add_handler (modules, "modified", + st->modules_handler_id = + gimp_container_add_handler (the_gimp->modules, "modified", G_CALLBACK (browser_info_update), st); - g_signal_connect (G_OBJECT (modules), "add", + g_signal_connect (G_OBJECT (the_gimp->modules), "add", G_CALLBACK (browser_info_add), st); - g_signal_connect (G_OBJECT (modules), "remove", + g_signal_connect (G_OBJECT (the_gimp->modules), "remove", G_CALLBACK (browser_info_remove), st); @@ -526,292 +184,7 @@ module_db_browser_new (void) } - -/**************************************************************/ -/* helper functions */ - - -/* name must be of the form lib*.so (Unix) or *.dll (Win32) */ -static gboolean -valid_module_name (const gchar *filename) -{ - gchar *basename; - gint len; - - basename = g_path_get_basename (filename); - - len = strlen (basename); - -#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) && !defined(__EMX__) - if (len < 3 + 1 + 3) - goto no_module; - - if (strncmp (basename, "lib", 3)) - goto no_module; - - if (strcmp (basename + len - 3, ".so")) - goto no_module; -#else - if (len < 1 + 4) - goto no_module; - - if (g_strcasecmp (basename + len - 4, ".dll")) - goto no_module; -#endif - - g_free (basename); - - return TRUE; - - no_module: - g_free (basename); - - return FALSE; -} - - -static gboolean -module_inhibited (const gchar *fullpath, - const gchar *inhibit_list) -{ - gchar *p; - gint pathlen; - const gchar *start; - const gchar *end; - - /* common case optimisation: the list is empty */ - if (!inhibit_list || *inhibit_list == '\000') - return FALSE; - - p = strstr (inhibit_list, fullpath); - 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 (fullpath); - if ((end - start) == pathlen) - return TRUE; - else - return FALSE; -} - - -static void -module_initialize (const gchar *filename, - gpointer loader_data) -{ - GimpModuleInfoObj *mod; - - if (!valid_module_name (filename)) - return; - - /* don't load if we already know about it */ - if (module_find_by_path (filename)) - return; - - mod = gimp_module_info_new (); - - mod->fullpath = g_strdup (filename); - mod->ondisk = TRUE; - mod->state = ST_MODULE_ERROR; - - mod->info = NULL; - mod->module = NULL; - mod->last_module_error = NULL; - mod->init = NULL; - mod->unload = NULL; - - /* Count of times main gimp is within the module. Normally, this - * will be 1, and we assume that the module won't call its - * unload callback until it is satisfied that it's not in use any - * more. refs can be 2 temporarily while we're running the module's - * unload function, to stop the module attempting to unload - * itself. - */ - mod->refs = 0; - - mod->load_inhibit = module_inhibited (mod->fullpath, - the_gimp->config->module_db_load_inhibit); - if (!mod->load_inhibit) - { - if (be_verbose) - g_print (_("load module: \"%s\"\n"), filename); - - mod_load (mod, TRUE); - } - else - { - if (be_verbose) - g_print (_("skipping module: \"%s\"\n"), filename); - - mod->state = ST_UNLOADED_OK; - } - - gimp_container_add (modules, GIMP_OBJECT (mod)); -} - -static void -mod_load (GimpModuleInfoObj *mod, - gboolean verbose) -{ - gpointer symbol; - - g_return_if_fail (mod->module == NULL); - - mod->module = g_module_open (mod->fullpath, G_MODULE_BIND_LAZY); - if (!mod->module) - { - mod->state = ST_MODULE_ERROR; - - if (mod->last_module_error) - g_free (mod->last_module_error); - mod->last_module_error = g_strdup (g_module_error ()); - - if (verbose) - g_warning (_("module load error: %s: %s"), - mod->fullpath, mod->last_module_error); - return; - } - -#ifdef __EMX__ - if (g_module_symbol (mod->module, "gimp_main_funcs", &symbol)) - { - *(struct main_funcs_struc **) symbol = gimp_main_funcs; - } -#endif - /* find the module_init symbol */ - if (!g_module_symbol (mod->module, "module_init", &symbol)) - { - mod->state = ST_MODULE_ERROR; - - if (mod->last_module_error) - g_free (mod->last_module_error); - mod->last_module_error = g_strdup ("missing module_init() symbol"); - - if (verbose) - g_warning ("%s: module_init() symbol not found", mod->fullpath); - - g_module_close (mod->module); - mod->module = NULL; - mod->info = NULL; - return; - } - - /* run module's initialisation */ - mod->init = symbol; - mod->info = NULL; - gimp_module_ref (mod); /* loaded modules are assumed to have a ref of 1 */ - if (mod->init (&mod->info) == GIMP_MODULE_UNLOAD) - { - mod->state = ST_LOAD_FAILED; - gimp_module_unref (mod); - mod->info = NULL; - return; - } - - /* module is now happy */ - mod->state = ST_LOADED_OK; - TRC (("loaded module %s, state at %p\n", mod->fullpath, mod)); - - /* do we have an unload function? */ - if (g_module_symbol (mod->module, "module_unload", &symbol)) - mod->unload = symbol; - else - mod->unload = NULL; -} - - -static void -mod_unload_completed_callback (gpointer data) -{ - GimpModuleInfoObj *mod = data; - - g_return_if_fail (mod->state == ST_UNLOAD_REQUESTED); - - /* lose the ref we gave this module when we loaded it, - * since the module's now happy to be unloaded. */ - gimp_module_unref (mod); - mod->info = NULL; - - mod->state = ST_UNLOADED_OK; - - TRC (("module unload completed callback for %p\n", mod)); - - gimp_module_info_modified (mod); -} - -static void -mod_unload (GimpModuleInfoObj *mod, - gboolean verbose) -{ - g_return_if_fail (mod->module != NULL); - g_return_if_fail (mod->unload != NULL); - - if (mod->state == ST_UNLOAD_REQUESTED) - return; - - mod->state = ST_UNLOAD_REQUESTED; - - TRC (("module unload requested for %p\n", mod)); - - /* 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_ref (mod); - mod->unload (mod->info->shutdown_data, mod_unload_completed_callback, mod); - - gtk_idle_add ((GtkFunction) mod_idle_unref, (gpointer) mod); -} - -static gboolean -mod_idle_unref (GimpModuleInfoObj *mod) -{ - gimp_module_unref (mod); - - return FALSE; -} - -#ifdef DUMP_DB -static void -print_module_info (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *i = data; - - g_print ("\n%s: %s\n", - i->fullpath, statename[i->state]); - g_print (" module:%p lasterr:%s init:%p unload:%p\n", - i->module, i->last_module_error? i->last_module_error : "NONE", - i->init, i->unload); - if (i->info) - { - g_print (" shutdown_data: %p\n" - " purpose: %s\n" - " author: %s\n" - " version: %s\n" - " copyright: %s\n" - " date: %s\n", - i->info->shutdown_data, - i->info->purpose, i->info->author, i->info->version, - i->info->copyright, i->info->date); - } -} -#endif - - - -/**************************************************************/ -/* UI functions */ +/* private functions */ static void browser_popdown_callback (GtkWidget *widget, @@ -824,13 +197,15 @@ static void browser_destroy_callback (GtkWidget *widget, gpointer data) { - g_signal_handlers_disconnect_by_func (G_OBJECT (modules), + BrowserState *st = data; + + g_signal_handlers_disconnect_by_func (G_OBJECT (the_gimp->modules), browser_info_add, data); - g_signal_handlers_disconnect_by_func (G_OBJECT (modules), + g_signal_handlers_disconnect_by_func (G_OBJECT (the_gimp->modules), browser_info_remove, data); - gimp_container_remove_handler (modules, modules_handler_id); + gimp_container_remove_handler (the_gimp->modules, st->modules_handler_id); g_free (data); } @@ -839,7 +214,7 @@ browser_load_inhibit_callback (GtkWidget *widget, gpointer data) { BrowserState *st = data; - gboolean new_value; + gboolean new_value; g_return_if_fail (st->last_update != NULL); @@ -851,24 +226,133 @@ browser_load_inhibit_callback (GtkWidget *widget, st->last_update->load_inhibit = new_value; gimp_module_info_modified (st->last_update); - need_to_rewrite_modulerc = TRUE; + the_gimp->write_modulerc = TRUE; } static void -browser_info_update (GimpModuleInfoObj *mod, - BrowserState *st) +browser_select_callback (GtkWidget *widget, + GtkWidget *child) { - gint i; + GimpModuleInfoObj *info; + BrowserState *st; + + info = g_object_get_data (G_OBJECT (child), "module_info"); + st = g_object_get_data (G_OBJECT (widget), "state"); + + if (st->last_update == info) + return; + + st->last_update = info; + + browser_info_update (st->last_update, st); +} + +static void +browser_load_unload_callback (GtkWidget *widget, + gpointer data) +{ + BrowserState *st = data; + + if (st->last_update->state == GIMP_MODULE_STATE_LOADED_OK) + gimp_module_info_module_unload (st->last_update, FALSE); + else + gimp_module_info_module_load (st->last_update, FALSE); + + gimp_module_info_modified (st->last_update); +} + +static void +browser_refresh_callback (GtkWidget *widget, + gpointer data) +{ + gimp_modules_refresh (the_gimp); +} + +static void +make_list_item (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *info = data; + BrowserState *st = user_data; + GtkWidget *list_item; + + if (!st->last_update) + st->last_update = info; + + list_item = gtk_list_item_new_with_label (info->fullpath); + + gtk_widget_show (list_item); + g_object_set_data (G_OBJECT (list_item), "module_info", info); + + gtk_container_add (GTK_CONTAINER (st->list), list_item); +} + +static void +browser_info_add (GimpContainer *container, + GimpModuleInfoObj *mod, + BrowserState *st) +{ + make_list_item (mod, st); +} + +static void +browser_info_remove (GimpContainer *container, + GimpModuleInfoObj *mod, + BrowserState *st) +{ + GList *dlist; + GList *free_list; + GtkWidget *list_item; + GimpModuleInfoObj *info; + + dlist = gtk_container_get_children (GTK_CONTAINER (st->list)); + free_list = dlist; + + while (dlist) + { + list_item = dlist->data; + + info = g_object_get_data (G_OBJECT (list_item), "module_info"); + g_return_if_fail (info != NULL); + + if (info == mod) + { + gtk_container_remove (GTK_CONTAINER (st->list), list_item); + g_list_free (free_list); + return; + } + + dlist = dlist->next; + } + + g_warning ("tried to remove module that wasn't in brower's list"); + g_list_free (free_list); +} + +static void +browser_info_update (GimpModuleInfoObj *mod, + BrowserState *st) +{ + gint i; const gchar *text[NUM_INFO_LINES - 1]; - gchar *status; + gchar *status; + + static const gchar * const statename[] = + { + N_("Module error"), + N_("Loaded OK"), + N_("Load failed"), + N_("Unload requested"), + N_("Unloaded OK") + }; /* only update the info if we're actually showing it */ if (mod != st->last_update) return; - if (!mod) + if (! mod) { - for (i=0; i < NUM_INFO_LINES; i++) + for (i = 0; i < NUM_INFO_LINES; i++) gtk_label_set_text (GTK_LABEL (st->label[i]), ""); gtk_label_set_text (GTK_LABEL(st->button_label), _("")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); @@ -883,7 +367,7 @@ browser_info_update (GimpModuleInfoObj *mod, text[2] = mod->info->version; text[3] = mod->info->copyright; text[4] = mod->info->date; - text[5] = mod->ondisk? _("on disk") : _("only in memory"); + text[5] = mod->on_disk? _("on disk") : _("only in memory"); } else { @@ -892,12 +376,14 @@ browser_info_update (GimpModuleInfoObj *mod, text[2] = "--"; text[3] = "--"; text[4] = "--"; - text[5] = mod->ondisk? _("on disk") : _("nowhere (click 'refresh')"); + text[5] = mod->on_disk? _("on disk") : _("nowhere (click 'refresh')"); } - if (mod->state == ST_MODULE_ERROR && mod->last_module_error) - status = g_strdup_printf ("%s (%s)", gettext (statename[mod->state]), - mod->last_module_error); + if (mod->state == GIMP_MODULE_STATE_ERROR && mod->last_module_error) + { + status = g_strdup_printf ("%s (%s)", gettext (statename[mod->state]), + mod->last_module_error); + } else { status = g_strdup (gettext (statename[mod->state])); @@ -919,19 +405,19 @@ browser_info_update (GimpModuleInfoObj *mod, /* work out what the button should do (if anything) */ switch (mod->state) { - case ST_MODULE_ERROR: - case ST_LOAD_FAILED: - case ST_UNLOADED_OK: + case GIMP_MODULE_STATE_ERROR: + case GIMP_MODULE_STATE_LOAD_FAILED: + case GIMP_MODULE_STATE_UNLOADED_OK: gtk_label_set_text (GTK_LABEL(st->button_label), _("Load")); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->ondisk); + gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->on_disk); break; - case ST_UNLOAD_REQUESTED: + case GIMP_MODULE_STATE_UNLOAD_REQUESTED: gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); break; - case ST_LOADED_OK: + case GIMP_MODULE_STATE_LOADED_OK: gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->unload? TRUE : FALSE); @@ -981,218 +467,3 @@ browser_info_init (BrowserState *st, g_signal_connect (G_OBJECT (st->load_inhibit_check), "toggled", G_CALLBACK (browser_load_inhibit_callback), st); } - -static void -browser_select_callback (GtkWidget *widget, - GtkWidget *child) -{ - GimpModuleInfoObj *info; - BrowserState *st; - - info = g_object_get_data (G_OBJECT (child), "module_info"); - st = g_object_get_data (G_OBJECT (widget), "state"); - - if (st->last_update == info) - return; - - st->last_update = info; - - browser_info_update (st->last_update, st); -} - - -static void -browser_load_unload_callback (GtkWidget *widget, - gpointer data) -{ - BrowserState *st = data; - - if (st->last_update->state == ST_LOADED_OK) - mod_unload (st->last_update, FALSE); - else - mod_load (st->last_update, FALSE); - - gimp_module_info_modified (st->last_update); -} - - -static void -make_list_item (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *info = data; - BrowserState *st = user_data; - GtkWidget *list_item; - - if (!st->last_update) - st->last_update = info; - - list_item = gtk_list_item_new_with_label (info->fullpath); - - gtk_widget_show (list_item); - g_object_set_data (G_OBJECT (list_item), "module_info", info); - - gtk_container_add (GTK_CONTAINER (st->list), list_item); -} - - -static void -browser_info_add (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st) -{ - make_list_item (mod, st); -} - - -static void -browser_info_remove (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st) -{ - GList *dlist; - GList *free_list; - GtkWidget *list_item; - GimpModuleInfoObj *info; - - dlist = gtk_container_get_children (GTK_CONTAINER (st->list)); - free_list = dlist; - - while (dlist) - { - list_item = dlist->data; - - info = g_object_get_data (G_OBJECT (list_item), "module_info"); - g_return_if_fail (info != NULL); - - if (info == mod) - { - gtk_container_remove (GTK_CONTAINER (st->list), list_item); - g_list_free (free_list); - return; - } - - dlist = dlist->next; - } - - g_warning ("tried to remove module that wasn't in brower's list"); - g_list_free (free_list); -} - - - -static void -module_db_module_ondisk (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - struct stat statbuf; - gint ret; - gint old_ondisk = mod->ondisk; - GSList **kill_list = user_data; - - ret = stat (mod->fullpath, &statbuf); - if (ret != 0) - mod->ondisk = FALSE; - else - mod->ondisk = TRUE; - - /* if it's not on the disk, and it isn't in memory, mark it to be - * removed later. */ - if (!mod->ondisk && !mod->module) - { - *kill_list = g_slist_append (*kill_list, mod); - mod = NULL; - } - - if (mod && mod->ondisk != old_ondisk) - gimp_module_info_modified (mod); -} - - -static void -module_db_module_remove (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - - gimp_container_remove (modules, GIMP_OBJECT (mod)); - - g_object_unref (G_OBJECT (mod)); -} - - - -typedef struct -{ - const gchar *search_key; - GimpModuleInfoObj *found; -} find_by_path_closure; - -static void -module_db_path_cmp (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - find_by_path_closure *cl = user_data; - - if (!strcmp (mod->fullpath, cl->search_key)) - cl->found = mod; -} - -static GimpModuleInfoObj * -module_find_by_path (const char *fullpath) -{ - find_by_path_closure cl; - - cl.found = NULL; - cl.search_key = fullpath; - - gimp_container_foreach (modules, module_db_path_cmp, &cl); - - return cl.found; -} - - - -static void -browser_refresh_callback (GtkWidget *widget, - gpointer data) -{ - GSList *kill_list = NULL; - - /* remove modules we don't have on disk anymore */ - gimp_container_foreach (modules, module_db_module_ondisk, &kill_list); - g_slist_foreach (kill_list, module_db_module_remove, NULL); - g_slist_free (kill_list); - kill_list = NULL; - - /* walk filesystem and add new things we find */ - gimp_datafiles_read_directories (the_gimp->config->module_path, 0 /* no flags */, - module_initialize, NULL); -} - - -static void -gimp_module_ref (GimpModuleInfoObj *mod) -{ - g_return_if_fail (mod->refs >= 0); - g_return_if_fail (mod->module != NULL); - mod->refs++; -} - -static void -gimp_module_unref (GimpModuleInfoObj *mod) -{ - g_return_if_fail (mod->refs > 0); - g_return_if_fail (mod->module != NULL); - - mod->refs--; - - if (mod->refs == 0) - { - TRC (("module %p refs hit 0, g_module_closing it\n", mod)); - g_module_close (mod->module); - mod->module = NULL; - } -} diff --git a/app/dialogs/module-dialog.h b/app/dialogs/module-dialog.h index fa1ecc49e2..65699e8523 100644 --- a/app/dialogs/module-dialog.h +++ b/app/dialogs/module-dialog.h @@ -1,7 +1,8 @@ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * - * module_db.h (C) 1999 Austin Donnelly + * module-browser.h + * (C) 1999 Austin Donnelly * * 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 @@ -18,16 +19,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __MODULE_DB_H__ +#ifndef __MODULE_BROWSER_H__ -/* Load any modules we find on the module-path set in the gimprc */ -void module_db_init (void); - -/* Unload all modules, in case a module needs some cleanups */ -void module_db_free (void); - -GtkWidget * module_db_browser_new (void); +GtkWidget * module_browser_new (void); -#endif /* __MODULE_DB_H__ */ +#endif /* __MODULE_BROWSER_H__ */ diff --git a/app/gui/Makefile.am b/app/gui/Makefile.am index c6533f6c92..2c1a150a84 100644 --- a/app/gui/Makefile.am +++ b/app/gui/Makefile.am @@ -71,6 +71,8 @@ libappgui_a_SOURCES = @STRIP_BEGIN@ \ layers-commands.h \ menus.c \ menus.h \ + module-browser.c \ + module-browser.h \ offset-dialog.c \ offset-dialog.h \ palette-editor.c \ diff --git a/app/gui/dialogs-constructors.c b/app/gui/dialogs-constructors.c index d612d974ab..3450adf995 100644 --- a/app/gui/dialogs-constructors.c +++ b/app/gui/dialogs-constructors.c @@ -64,6 +64,7 @@ #include "gradients-commands.h" #include "layers-commands.h" #include "menus.h" +#include "module-browser.h" #include "palette-editor.h" #include "palette-select.h" #include "palettes-commands.h" @@ -79,7 +80,6 @@ #include "devices.h" #include "docindex.h" #include "gimprc.h" -#include "module_db.h" #include "undo_history.h" #ifdef DISPLAY_FILTERS @@ -230,7 +230,7 @@ GtkWidget * dialogs_module_browser_get (GimpDialogFactory *factory, GimpContext *context) { - return module_db_browser_new (); + return module_browser_new (); } GtkWidget * diff --git a/app/gui/module-browser.c b/app/gui/module-browser.c index 77f4ee98c7..d6ad2156a1 100644 --- a/app/gui/module-browser.c +++ b/app/gui/module-browser.c @@ -1,7 +1,8 @@ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * - * module_db.c (C) 1999 Austin Donnelly + * module-browser.c + * (C) 1999 Austin Donnelly * * 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 @@ -20,421 +21,78 @@ #include "config.h" -#include - -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - #include -#include "libgimpbase/gimpbase.h" #include "libgimpwidgets/gimpwidgets.h" -#include "core/core-types.h" +#include "gui-types.h" #include "core/gimp.h" -#include "core/gimpcoreconfig.h" -#include "core/gimpdatafiles.h" -#include "core/gimplist.h" +#include "core/gimpcontainer.h" +#include "core/gimpmoduleinfo.h" +#include "core/gimpmodules.h" + +#include "module-browser.h" #include "app_procs.h" -#include "appenv.h" -#include "module_db.h" -#include "gimprc.h" - -#include "libgimp/gimpmodule.h" #include "libgimp/gimpintl.h" -/* debug control: */ - -/*#define DUMP_DB*/ -/*#define DEBUG*/ - -#ifdef DEBUG -#undef DUMP_DB -#define DUMP_DB -#define TRC(x) printf x -#else -#define TRC(x) -#endif - - -typedef enum -{ - ST_MODULE_ERROR, /* missing module_load function or other error */ - ST_LOADED_OK, /* happy and running (normal state of affairs) */ - ST_LOAD_FAILED, /* module_load returned GIMP_MODULE_UNLOAD */ - ST_UNLOAD_REQUESTED, /* sent unload request, waiting for callback */ - ST_UNLOADED_OK /* callback arrived, module not in memory anymore */ -} module_state; - -enum -{ - MODIFIED, - LAST_SIGNAL -}; - - -#define GIMP_TYPE_MODULE_INFO (gimp_module_info_get_type ()) -#define GIMP_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObj)) -#define GIMP_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) -#define GIMP_IS_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_MODULE_INFO)) -#define GIMP_IS_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MODULE_INFO)) -#define GIMP_MODULE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) - - -typedef struct _GimpModuleInfoObj GimpModuleInfoObj; -typedef struct _GimpModuleInfoObjClass GimpModuleInfoObjClass; - -struct _GimpModuleInfoObj -{ - GimpObject parent_instance; - - gchar *fullpath; /* path to the module */ - module_state state; /* what's happened to the module */ - gboolean ondisk; /* TRUE if file still exists */ - gboolean load_inhibit; /* user requests not to load at boot time */ - gint refs; /* how many time we're running in the module */ - - /* stuff from now on may be NULL depending on the state the module is in */ - GimpModuleInfo *info; /* returned values from module_init */ - GModule *module; /* handle on the module */ - gchar *last_module_error; - - GimpModuleInitFunc init; - GimpModuleUnloadFunc unload; -}; - -struct _GimpModuleInfoObjClass -{ - GimpObjectClass parent_class; - - void (* modified) (GimpModuleInfoObj *module_info); -}; - - -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 guint module_info_signals[LAST_SIGNAL]; - -static GimpObjectClass *parent_class = NULL; - - -static 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; - - object_class = G_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, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - object_class->finalize = gimp_module_info_finalize; - - klass->modified = NULL; -} - -static void -gimp_module_info_init (GimpModuleInfoObj *mod) -{ - /* don't need to do anything */ -} - -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); -} - -/* exported API: */ - -static void -gimp_module_info_modified (GimpModuleInfoObj *mod) -{ - g_signal_emit (G_OBJECT (mod), module_info_signals[MODIFIED], 0); -} - -static GimpModuleInfoObj * -gimp_module_info_new (void) -{ - return GIMP_MODULE_INFO (g_object_new (GIMP_TYPE_MODULE_INFO, NULL)); -} - - -/* dialog stuff */ - -static const gchar * const statename[] = -{ - N_("Module error"), - N_("Loaded OK"), - N_("Load failed"), - N_("Unload requested"), - N_("Unloaded OK") -}; - -#ifdef __EMX__ -extern void gimp_color_selector_register (); -extern void gimp_color_selector_unregister (); -extern void dialog_register (); -extern void dialog_unregister (); - -static struct main_funcs_struc -{ - gchar *name; - void (*func) (); -} - -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 - - #define NUM_INFO_LINES 7 typedef struct { - GtkWidget *table; - GtkWidget *label[NUM_INFO_LINES]; - GtkWidget *button_label; + GtkWidget *table; + GtkWidget *label[NUM_INFO_LINES]; + GtkWidget *button_label; GimpModuleInfoObj *last_update; - GtkWidget *button; - GtkWidget *list; - GtkWidget *load_inhibit_check; + GtkWidget *button; + GtkWidget *list; + GtkWidget *load_inhibit_check; + + GQuark modules_handler_id; } BrowserState; -/* prototypes */ -static void module_initialize (const gchar *filename, - gpointer loader_data); -static void mod_load (GimpModuleInfoObj *mod, - gboolean verbose); -static void mod_unload (GimpModuleInfoObj *mod, - gboolean verbose); -static gboolean mod_idle_unref (GimpModuleInfoObj *mod); -static GimpModuleInfoObj * module_find_by_path (const gchar *fullpath); +/* local function prototypes */ -#ifdef DUMP_DB -static void print_module_info (gpointer data, - gpointer user_data); -#endif - -static void browser_popdown_callback (GtkWidget *widget, - gpointer data); -static void browser_destroy_callback (GtkWidget *widget, - gpointer data); -static void browser_info_update (GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_add (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_remove (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_init (BrowserState *st, - GtkWidget *table); -static void browser_select_callback (GtkWidget *widget, - GtkWidget *child); -static void browser_load_unload_callback (GtkWidget *widget, - gpointer data); -static void browser_refresh_callback (GtkWidget *widget, - gpointer data); -static void make_list_item (gpointer data, - gpointer user_data); - -static void gimp_module_ref (GimpModuleInfoObj *mod); -static void gimp_module_unref (GimpModuleInfoObj *mod); +static void browser_popdown_callback (GtkWidget *widget, + gpointer data); +static void browser_destroy_callback (GtkWidget *widget, + gpointer data); +static void browser_load_inhibit_callback (GtkWidget *widget, + gpointer data); +static void browser_select_callback (GtkWidget *widget, + GtkWidget *child); +static void browser_load_unload_callback (GtkWidget *widget, + gpointer data); +static void browser_refresh_callback (GtkWidget *widget, + gpointer data); +static void make_list_item (gpointer data, + gpointer user_data); +static void browser_info_add (GimpContainer *container, + GimpModuleInfoObj *mod, + BrowserState *st); +static void browser_info_remove (GimpContainer *container, + GimpModuleInfoObj *mod, + BrowserState *st); +static void browser_info_update (GimpModuleInfoObj *mod, + BrowserState *st); +static void browser_info_init (BrowserState *st, + GtkWidget *table); - -/* global set of module_info pointers */ -static GimpContainer *modules; -static GQuark modules_handler_id; - -/* If the inhibit state of any modules changes, we might need to - * re-write the modulerc. - */ -static gboolean need_to_rewrite_modulerc = FALSE; - - -/**************************************************************/ -/* Exported functions */ - -void -module_db_init (void) -{ - gchar *filename; - - /* load the modulerc file */ - filename = gimp_personal_rc_file ("modulerc"); - gimprc_parse_file (filename); - g_free (filename); - - /* Load and initialize gimp modules */ - - modules = gimp_list_new (GIMP_TYPE_MODULE_INFO, GIMP_CONTAINER_POLICY_WEAK); - - if (g_module_supported ()) - gimp_datafiles_read_directories (the_gimp->config->module_path, 0 /* no flags */, - module_initialize, NULL); -#ifdef DUMP_DB - gimp_container_foreach (modules, print_module_info, NULL); -#endif -} - -static void -free_a_single_module (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - - if (mod->module && mod->unload && mod->state == ST_LOADED_OK) - { - mod_unload (mod, FALSE); - } -} - -static void -add_to_inhibit_string (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - GString *str = user_data; - - if (mod->load_inhibit) - { - str = g_string_append_c (str, G_SEARCHPATH_SEPARATOR); - str = g_string_append (str, mod->fullpath); - } -} - - -static gboolean -module_db_write_modulerc (void) -{ - GString *str; - gchar *p; - gchar *filename; - FILE *fp; - gboolean saved = FALSE; - - str = g_string_new (NULL); - gimp_container_foreach (modules, add_to_inhibit_string, str); - if (str->len > 0) - p = str->str + 1; - else - p = ""; - - filename = gimp_personal_rc_file ("modulerc"); - fp = fopen (filename, "wt"); - g_free (filename); - if (fp) - { - fprintf (fp, "(module-load-inhibit \"%s\")\n", p); - fclose (fp); - saved = TRUE; - } - - g_string_free (str, TRUE); - return (saved); -} - - -void -module_db_free (void) -{ - if (need_to_rewrite_modulerc) - { - if (module_db_write_modulerc ()) - { - need_to_rewrite_modulerc = FALSE; - } - } - gimp_container_foreach (modules, free_a_single_module, NULL); -} - +/* public functions */ GtkWidget * -module_db_browser_new (void) +module_browser_new (void) { - GtkWidget *shell; - GtkWidget *hbox; - GtkWidget *vbox; - GtkWidget *listbox; - GtkWidget *button; + GtkWidget *shell; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *listbox; + GtkWidget *button; BrowserState *st; shell = gimp_dialog_new (_("Module DB"), "module_db_dialog", @@ -468,7 +126,7 @@ module_db_browser_new (void) gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), st->list); - gimp_container_foreach (modules, make_list_item, st); + gimp_container_foreach (the_gimp->modules, make_list_item, st); gtk_widget_show (st->list); @@ -507,14 +165,14 @@ module_db_browser_new (void) /* hook the GimpContainer signals so we can refresh the display * appropriately. */ - modules_handler_id = - gimp_container_add_handler (modules, "modified", + st->modules_handler_id = + gimp_container_add_handler (the_gimp->modules, "modified", G_CALLBACK (browser_info_update), st); - g_signal_connect (G_OBJECT (modules), "add", + g_signal_connect (G_OBJECT (the_gimp->modules), "add", G_CALLBACK (browser_info_add), st); - g_signal_connect (G_OBJECT (modules), "remove", + g_signal_connect (G_OBJECT (the_gimp->modules), "remove", G_CALLBACK (browser_info_remove), st); @@ -526,292 +184,7 @@ module_db_browser_new (void) } - -/**************************************************************/ -/* helper functions */ - - -/* name must be of the form lib*.so (Unix) or *.dll (Win32) */ -static gboolean -valid_module_name (const gchar *filename) -{ - gchar *basename; - gint len; - - basename = g_path_get_basename (filename); - - len = strlen (basename); - -#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) && !defined(__EMX__) - if (len < 3 + 1 + 3) - goto no_module; - - if (strncmp (basename, "lib", 3)) - goto no_module; - - if (strcmp (basename + len - 3, ".so")) - goto no_module; -#else - if (len < 1 + 4) - goto no_module; - - if (g_strcasecmp (basename + len - 4, ".dll")) - goto no_module; -#endif - - g_free (basename); - - return TRUE; - - no_module: - g_free (basename); - - return FALSE; -} - - -static gboolean -module_inhibited (const gchar *fullpath, - const gchar *inhibit_list) -{ - gchar *p; - gint pathlen; - const gchar *start; - const gchar *end; - - /* common case optimisation: the list is empty */ - if (!inhibit_list || *inhibit_list == '\000') - return FALSE; - - p = strstr (inhibit_list, fullpath); - 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 (fullpath); - if ((end - start) == pathlen) - return TRUE; - else - return FALSE; -} - - -static void -module_initialize (const gchar *filename, - gpointer loader_data) -{ - GimpModuleInfoObj *mod; - - if (!valid_module_name (filename)) - return; - - /* don't load if we already know about it */ - if (module_find_by_path (filename)) - return; - - mod = gimp_module_info_new (); - - mod->fullpath = g_strdup (filename); - mod->ondisk = TRUE; - mod->state = ST_MODULE_ERROR; - - mod->info = NULL; - mod->module = NULL; - mod->last_module_error = NULL; - mod->init = NULL; - mod->unload = NULL; - - /* Count of times main gimp is within the module. Normally, this - * will be 1, and we assume that the module won't call its - * unload callback until it is satisfied that it's not in use any - * more. refs can be 2 temporarily while we're running the module's - * unload function, to stop the module attempting to unload - * itself. - */ - mod->refs = 0; - - mod->load_inhibit = module_inhibited (mod->fullpath, - the_gimp->config->module_db_load_inhibit); - if (!mod->load_inhibit) - { - if (be_verbose) - g_print (_("load module: \"%s\"\n"), filename); - - mod_load (mod, TRUE); - } - else - { - if (be_verbose) - g_print (_("skipping module: \"%s\"\n"), filename); - - mod->state = ST_UNLOADED_OK; - } - - gimp_container_add (modules, GIMP_OBJECT (mod)); -} - -static void -mod_load (GimpModuleInfoObj *mod, - gboolean verbose) -{ - gpointer symbol; - - g_return_if_fail (mod->module == NULL); - - mod->module = g_module_open (mod->fullpath, G_MODULE_BIND_LAZY); - if (!mod->module) - { - mod->state = ST_MODULE_ERROR; - - if (mod->last_module_error) - g_free (mod->last_module_error); - mod->last_module_error = g_strdup (g_module_error ()); - - if (verbose) - g_warning (_("module load error: %s: %s"), - mod->fullpath, mod->last_module_error); - return; - } - -#ifdef __EMX__ - if (g_module_symbol (mod->module, "gimp_main_funcs", &symbol)) - { - *(struct main_funcs_struc **) symbol = gimp_main_funcs; - } -#endif - /* find the module_init symbol */ - if (!g_module_symbol (mod->module, "module_init", &symbol)) - { - mod->state = ST_MODULE_ERROR; - - if (mod->last_module_error) - g_free (mod->last_module_error); - mod->last_module_error = g_strdup ("missing module_init() symbol"); - - if (verbose) - g_warning ("%s: module_init() symbol not found", mod->fullpath); - - g_module_close (mod->module); - mod->module = NULL; - mod->info = NULL; - return; - } - - /* run module's initialisation */ - mod->init = symbol; - mod->info = NULL; - gimp_module_ref (mod); /* loaded modules are assumed to have a ref of 1 */ - if (mod->init (&mod->info) == GIMP_MODULE_UNLOAD) - { - mod->state = ST_LOAD_FAILED; - gimp_module_unref (mod); - mod->info = NULL; - return; - } - - /* module is now happy */ - mod->state = ST_LOADED_OK; - TRC (("loaded module %s, state at %p\n", mod->fullpath, mod)); - - /* do we have an unload function? */ - if (g_module_symbol (mod->module, "module_unload", &symbol)) - mod->unload = symbol; - else - mod->unload = NULL; -} - - -static void -mod_unload_completed_callback (gpointer data) -{ - GimpModuleInfoObj *mod = data; - - g_return_if_fail (mod->state == ST_UNLOAD_REQUESTED); - - /* lose the ref we gave this module when we loaded it, - * since the module's now happy to be unloaded. */ - gimp_module_unref (mod); - mod->info = NULL; - - mod->state = ST_UNLOADED_OK; - - TRC (("module unload completed callback for %p\n", mod)); - - gimp_module_info_modified (mod); -} - -static void -mod_unload (GimpModuleInfoObj *mod, - gboolean verbose) -{ - g_return_if_fail (mod->module != NULL); - g_return_if_fail (mod->unload != NULL); - - if (mod->state == ST_UNLOAD_REQUESTED) - return; - - mod->state = ST_UNLOAD_REQUESTED; - - TRC (("module unload requested for %p\n", mod)); - - /* 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_ref (mod); - mod->unload (mod->info->shutdown_data, mod_unload_completed_callback, mod); - - gtk_idle_add ((GtkFunction) mod_idle_unref, (gpointer) mod); -} - -static gboolean -mod_idle_unref (GimpModuleInfoObj *mod) -{ - gimp_module_unref (mod); - - return FALSE; -} - -#ifdef DUMP_DB -static void -print_module_info (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *i = data; - - g_print ("\n%s: %s\n", - i->fullpath, statename[i->state]); - g_print (" module:%p lasterr:%s init:%p unload:%p\n", - i->module, i->last_module_error? i->last_module_error : "NONE", - i->init, i->unload); - if (i->info) - { - g_print (" shutdown_data: %p\n" - " purpose: %s\n" - " author: %s\n" - " version: %s\n" - " copyright: %s\n" - " date: %s\n", - i->info->shutdown_data, - i->info->purpose, i->info->author, i->info->version, - i->info->copyright, i->info->date); - } -} -#endif - - - -/**************************************************************/ -/* UI functions */ +/* private functions */ static void browser_popdown_callback (GtkWidget *widget, @@ -824,13 +197,15 @@ static void browser_destroy_callback (GtkWidget *widget, gpointer data) { - g_signal_handlers_disconnect_by_func (G_OBJECT (modules), + BrowserState *st = data; + + g_signal_handlers_disconnect_by_func (G_OBJECT (the_gimp->modules), browser_info_add, data); - g_signal_handlers_disconnect_by_func (G_OBJECT (modules), + g_signal_handlers_disconnect_by_func (G_OBJECT (the_gimp->modules), browser_info_remove, data); - gimp_container_remove_handler (modules, modules_handler_id); + gimp_container_remove_handler (the_gimp->modules, st->modules_handler_id); g_free (data); } @@ -839,7 +214,7 @@ browser_load_inhibit_callback (GtkWidget *widget, gpointer data) { BrowserState *st = data; - gboolean new_value; + gboolean new_value; g_return_if_fail (st->last_update != NULL); @@ -851,24 +226,133 @@ browser_load_inhibit_callback (GtkWidget *widget, st->last_update->load_inhibit = new_value; gimp_module_info_modified (st->last_update); - need_to_rewrite_modulerc = TRUE; + the_gimp->write_modulerc = TRUE; } static void -browser_info_update (GimpModuleInfoObj *mod, - BrowserState *st) +browser_select_callback (GtkWidget *widget, + GtkWidget *child) { - gint i; + GimpModuleInfoObj *info; + BrowserState *st; + + info = g_object_get_data (G_OBJECT (child), "module_info"); + st = g_object_get_data (G_OBJECT (widget), "state"); + + if (st->last_update == info) + return; + + st->last_update = info; + + browser_info_update (st->last_update, st); +} + +static void +browser_load_unload_callback (GtkWidget *widget, + gpointer data) +{ + BrowserState *st = data; + + if (st->last_update->state == GIMP_MODULE_STATE_LOADED_OK) + gimp_module_info_module_unload (st->last_update, FALSE); + else + gimp_module_info_module_load (st->last_update, FALSE); + + gimp_module_info_modified (st->last_update); +} + +static void +browser_refresh_callback (GtkWidget *widget, + gpointer data) +{ + gimp_modules_refresh (the_gimp); +} + +static void +make_list_item (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *info = data; + BrowserState *st = user_data; + GtkWidget *list_item; + + if (!st->last_update) + st->last_update = info; + + list_item = gtk_list_item_new_with_label (info->fullpath); + + gtk_widget_show (list_item); + g_object_set_data (G_OBJECT (list_item), "module_info", info); + + gtk_container_add (GTK_CONTAINER (st->list), list_item); +} + +static void +browser_info_add (GimpContainer *container, + GimpModuleInfoObj *mod, + BrowserState *st) +{ + make_list_item (mod, st); +} + +static void +browser_info_remove (GimpContainer *container, + GimpModuleInfoObj *mod, + BrowserState *st) +{ + GList *dlist; + GList *free_list; + GtkWidget *list_item; + GimpModuleInfoObj *info; + + dlist = gtk_container_get_children (GTK_CONTAINER (st->list)); + free_list = dlist; + + while (dlist) + { + list_item = dlist->data; + + info = g_object_get_data (G_OBJECT (list_item), "module_info"); + g_return_if_fail (info != NULL); + + if (info == mod) + { + gtk_container_remove (GTK_CONTAINER (st->list), list_item); + g_list_free (free_list); + return; + } + + dlist = dlist->next; + } + + g_warning ("tried to remove module that wasn't in brower's list"); + g_list_free (free_list); +} + +static void +browser_info_update (GimpModuleInfoObj *mod, + BrowserState *st) +{ + gint i; const gchar *text[NUM_INFO_LINES - 1]; - gchar *status; + gchar *status; + + static const gchar * const statename[] = + { + N_("Module error"), + N_("Loaded OK"), + N_("Load failed"), + N_("Unload requested"), + N_("Unloaded OK") + }; /* only update the info if we're actually showing it */ if (mod != st->last_update) return; - if (!mod) + if (! mod) { - for (i=0; i < NUM_INFO_LINES; i++) + for (i = 0; i < NUM_INFO_LINES; i++) gtk_label_set_text (GTK_LABEL (st->label[i]), ""); gtk_label_set_text (GTK_LABEL(st->button_label), _("")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); @@ -883,7 +367,7 @@ browser_info_update (GimpModuleInfoObj *mod, text[2] = mod->info->version; text[3] = mod->info->copyright; text[4] = mod->info->date; - text[5] = mod->ondisk? _("on disk") : _("only in memory"); + text[5] = mod->on_disk? _("on disk") : _("only in memory"); } else { @@ -892,12 +376,14 @@ browser_info_update (GimpModuleInfoObj *mod, text[2] = "--"; text[3] = "--"; text[4] = "--"; - text[5] = mod->ondisk? _("on disk") : _("nowhere (click 'refresh')"); + text[5] = mod->on_disk? _("on disk") : _("nowhere (click 'refresh')"); } - if (mod->state == ST_MODULE_ERROR && mod->last_module_error) - status = g_strdup_printf ("%s (%s)", gettext (statename[mod->state]), - mod->last_module_error); + if (mod->state == GIMP_MODULE_STATE_ERROR && mod->last_module_error) + { + status = g_strdup_printf ("%s (%s)", gettext (statename[mod->state]), + mod->last_module_error); + } else { status = g_strdup (gettext (statename[mod->state])); @@ -919,19 +405,19 @@ browser_info_update (GimpModuleInfoObj *mod, /* work out what the button should do (if anything) */ switch (mod->state) { - case ST_MODULE_ERROR: - case ST_LOAD_FAILED: - case ST_UNLOADED_OK: + case GIMP_MODULE_STATE_ERROR: + case GIMP_MODULE_STATE_LOAD_FAILED: + case GIMP_MODULE_STATE_UNLOADED_OK: gtk_label_set_text (GTK_LABEL(st->button_label), _("Load")); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->ondisk); + gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->on_disk); break; - case ST_UNLOAD_REQUESTED: + case GIMP_MODULE_STATE_UNLOAD_REQUESTED: gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); break; - case ST_LOADED_OK: + case GIMP_MODULE_STATE_LOADED_OK: gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->unload? TRUE : FALSE); @@ -981,218 +467,3 @@ browser_info_init (BrowserState *st, g_signal_connect (G_OBJECT (st->load_inhibit_check), "toggled", G_CALLBACK (browser_load_inhibit_callback), st); } - -static void -browser_select_callback (GtkWidget *widget, - GtkWidget *child) -{ - GimpModuleInfoObj *info; - BrowserState *st; - - info = g_object_get_data (G_OBJECT (child), "module_info"); - st = g_object_get_data (G_OBJECT (widget), "state"); - - if (st->last_update == info) - return; - - st->last_update = info; - - browser_info_update (st->last_update, st); -} - - -static void -browser_load_unload_callback (GtkWidget *widget, - gpointer data) -{ - BrowserState *st = data; - - if (st->last_update->state == ST_LOADED_OK) - mod_unload (st->last_update, FALSE); - else - mod_load (st->last_update, FALSE); - - gimp_module_info_modified (st->last_update); -} - - -static void -make_list_item (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *info = data; - BrowserState *st = user_data; - GtkWidget *list_item; - - if (!st->last_update) - st->last_update = info; - - list_item = gtk_list_item_new_with_label (info->fullpath); - - gtk_widget_show (list_item); - g_object_set_data (G_OBJECT (list_item), "module_info", info); - - gtk_container_add (GTK_CONTAINER (st->list), list_item); -} - - -static void -browser_info_add (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st) -{ - make_list_item (mod, st); -} - - -static void -browser_info_remove (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st) -{ - GList *dlist; - GList *free_list; - GtkWidget *list_item; - GimpModuleInfoObj *info; - - dlist = gtk_container_get_children (GTK_CONTAINER (st->list)); - free_list = dlist; - - while (dlist) - { - list_item = dlist->data; - - info = g_object_get_data (G_OBJECT (list_item), "module_info"); - g_return_if_fail (info != NULL); - - if (info == mod) - { - gtk_container_remove (GTK_CONTAINER (st->list), list_item); - g_list_free (free_list); - return; - } - - dlist = dlist->next; - } - - g_warning ("tried to remove module that wasn't in brower's list"); - g_list_free (free_list); -} - - - -static void -module_db_module_ondisk (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - struct stat statbuf; - gint ret; - gint old_ondisk = mod->ondisk; - GSList **kill_list = user_data; - - ret = stat (mod->fullpath, &statbuf); - if (ret != 0) - mod->ondisk = FALSE; - else - mod->ondisk = TRUE; - - /* if it's not on the disk, and it isn't in memory, mark it to be - * removed later. */ - if (!mod->ondisk && !mod->module) - { - *kill_list = g_slist_append (*kill_list, mod); - mod = NULL; - } - - if (mod && mod->ondisk != old_ondisk) - gimp_module_info_modified (mod); -} - - -static void -module_db_module_remove (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - - gimp_container_remove (modules, GIMP_OBJECT (mod)); - - g_object_unref (G_OBJECT (mod)); -} - - - -typedef struct -{ - const gchar *search_key; - GimpModuleInfoObj *found; -} find_by_path_closure; - -static void -module_db_path_cmp (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - find_by_path_closure *cl = user_data; - - if (!strcmp (mod->fullpath, cl->search_key)) - cl->found = mod; -} - -static GimpModuleInfoObj * -module_find_by_path (const char *fullpath) -{ - find_by_path_closure cl; - - cl.found = NULL; - cl.search_key = fullpath; - - gimp_container_foreach (modules, module_db_path_cmp, &cl); - - return cl.found; -} - - - -static void -browser_refresh_callback (GtkWidget *widget, - gpointer data) -{ - GSList *kill_list = NULL; - - /* remove modules we don't have on disk anymore */ - gimp_container_foreach (modules, module_db_module_ondisk, &kill_list); - g_slist_foreach (kill_list, module_db_module_remove, NULL); - g_slist_free (kill_list); - kill_list = NULL; - - /* walk filesystem and add new things we find */ - gimp_datafiles_read_directories (the_gimp->config->module_path, 0 /* no flags */, - module_initialize, NULL); -} - - -static void -gimp_module_ref (GimpModuleInfoObj *mod) -{ - g_return_if_fail (mod->refs >= 0); - g_return_if_fail (mod->module != NULL); - mod->refs++; -} - -static void -gimp_module_unref (GimpModuleInfoObj *mod) -{ - g_return_if_fail (mod->refs > 0); - g_return_if_fail (mod->module != NULL); - - mod->refs--; - - if (mod->refs == 0) - { - TRC (("module %p refs hit 0, g_module_closing it\n", mod)); - g_module_close (mod->module); - mod->module = NULL; - } -} diff --git a/app/gui/module-browser.h b/app/gui/module-browser.h index fa1ecc49e2..65699e8523 100644 --- a/app/gui/module-browser.h +++ b/app/gui/module-browser.h @@ -1,7 +1,8 @@ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * - * module_db.h (C) 1999 Austin Donnelly + * module-browser.h + * (C) 1999 Austin Donnelly * * 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 @@ -18,16 +19,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __MODULE_DB_H__ +#ifndef __MODULE_BROWSER_H__ -/* Load any modules we find on the module-path set in the gimprc */ -void module_db_init (void); - -/* Unload all modules, in case a module needs some cleanups */ -void module_db_free (void); - -GtkWidget * module_db_browser_new (void); +GtkWidget * module_browser_new (void); -#endif /* __MODULE_DB_H__ */ +#endif /* __MODULE_BROWSER_H__ */ diff --git a/app/module_db.c b/app/module_db.c deleted file mode 100644 index 77f4ee98c7..0000000000 --- a/app/module_db.c +++ /dev/null @@ -1,1198 +0,0 @@ -/* The GIMP -- an image manipulation program - * Copyright (C) 1995 Spencer Kimball and Peter Mattis - * - * module_db.c (C) 1999 Austin Donnelly - * - * 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 - -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -#include - -#include "libgimpbase/gimpbase.h" -#include "libgimpwidgets/gimpwidgets.h" - -#include "core/core-types.h" - -#include "core/gimp.h" -#include "core/gimpcoreconfig.h" -#include "core/gimpdatafiles.h" -#include "core/gimplist.h" - -#include "app_procs.h" -#include "appenv.h" -#include "module_db.h" -#include "gimprc.h" - -#include "libgimp/gimpmodule.h" - -#include "libgimp/gimpintl.h" - - -/* debug control: */ - -/*#define DUMP_DB*/ -/*#define DEBUG*/ - -#ifdef DEBUG -#undef DUMP_DB -#define DUMP_DB -#define TRC(x) printf x -#else -#define TRC(x) -#endif - - -typedef enum -{ - ST_MODULE_ERROR, /* missing module_load function or other error */ - ST_LOADED_OK, /* happy and running (normal state of affairs) */ - ST_LOAD_FAILED, /* module_load returned GIMP_MODULE_UNLOAD */ - ST_UNLOAD_REQUESTED, /* sent unload request, waiting for callback */ - ST_UNLOADED_OK /* callback arrived, module not in memory anymore */ -} module_state; - -enum -{ - MODIFIED, - LAST_SIGNAL -}; - - -#define GIMP_TYPE_MODULE_INFO (gimp_module_info_get_type ()) -#define GIMP_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObj)) -#define GIMP_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) -#define GIMP_IS_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_MODULE_INFO)) -#define GIMP_IS_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MODULE_INFO)) -#define GIMP_MODULE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) - - -typedef struct _GimpModuleInfoObj GimpModuleInfoObj; -typedef struct _GimpModuleInfoObjClass GimpModuleInfoObjClass; - -struct _GimpModuleInfoObj -{ - GimpObject parent_instance; - - gchar *fullpath; /* path to the module */ - module_state state; /* what's happened to the module */ - gboolean ondisk; /* TRUE if file still exists */ - gboolean load_inhibit; /* user requests not to load at boot time */ - gint refs; /* how many time we're running in the module */ - - /* stuff from now on may be NULL depending on the state the module is in */ - GimpModuleInfo *info; /* returned values from module_init */ - GModule *module; /* handle on the module */ - gchar *last_module_error; - - GimpModuleInitFunc init; - GimpModuleUnloadFunc unload; -}; - -struct _GimpModuleInfoObjClass -{ - GimpObjectClass parent_class; - - void (* modified) (GimpModuleInfoObj *module_info); -}; - - -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 guint module_info_signals[LAST_SIGNAL]; - -static GimpObjectClass *parent_class = NULL; - - -static 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; - - object_class = G_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, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - object_class->finalize = gimp_module_info_finalize; - - klass->modified = NULL; -} - -static void -gimp_module_info_init (GimpModuleInfoObj *mod) -{ - /* don't need to do anything */ -} - -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); -} - -/* exported API: */ - -static void -gimp_module_info_modified (GimpModuleInfoObj *mod) -{ - g_signal_emit (G_OBJECT (mod), module_info_signals[MODIFIED], 0); -} - -static GimpModuleInfoObj * -gimp_module_info_new (void) -{ - return GIMP_MODULE_INFO (g_object_new (GIMP_TYPE_MODULE_INFO, NULL)); -} - - -/* dialog stuff */ - -static const gchar * const statename[] = -{ - N_("Module error"), - N_("Loaded OK"), - N_("Load failed"), - N_("Unload requested"), - N_("Unloaded OK") -}; - -#ifdef __EMX__ -extern void gimp_color_selector_register (); -extern void gimp_color_selector_unregister (); -extern void dialog_register (); -extern void dialog_unregister (); - -static struct main_funcs_struc -{ - gchar *name; - void (*func) (); -} - -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 - - -#define NUM_INFO_LINES 7 - -typedef struct -{ - GtkWidget *table; - GtkWidget *label[NUM_INFO_LINES]; - GtkWidget *button_label; - GimpModuleInfoObj *last_update; - GtkWidget *button; - GtkWidget *list; - GtkWidget *load_inhibit_check; -} BrowserState; - - -/* prototypes */ -static void module_initialize (const gchar *filename, - gpointer loader_data); -static void mod_load (GimpModuleInfoObj *mod, - gboolean verbose); -static void mod_unload (GimpModuleInfoObj *mod, - gboolean verbose); -static gboolean mod_idle_unref (GimpModuleInfoObj *mod); -static GimpModuleInfoObj * module_find_by_path (const gchar *fullpath); - -#ifdef DUMP_DB -static void print_module_info (gpointer data, - gpointer user_data); -#endif - -static void browser_popdown_callback (GtkWidget *widget, - gpointer data); -static void browser_destroy_callback (GtkWidget *widget, - gpointer data); -static void browser_info_update (GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_add (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_remove (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st); -static void browser_info_init (BrowserState *st, - GtkWidget *table); -static void browser_select_callback (GtkWidget *widget, - GtkWidget *child); -static void browser_load_unload_callback (GtkWidget *widget, - gpointer data); -static void browser_refresh_callback (GtkWidget *widget, - gpointer data); -static void make_list_item (gpointer data, - gpointer user_data); - -static void gimp_module_ref (GimpModuleInfoObj *mod); -static void gimp_module_unref (GimpModuleInfoObj *mod); - - - -/* global set of module_info pointers */ -static GimpContainer *modules; -static GQuark modules_handler_id; - -/* If the inhibit state of any modules changes, we might need to - * re-write the modulerc. - */ -static gboolean need_to_rewrite_modulerc = FALSE; - - -/**************************************************************/ -/* Exported functions */ - -void -module_db_init (void) -{ - gchar *filename; - - /* load the modulerc file */ - filename = gimp_personal_rc_file ("modulerc"); - gimprc_parse_file (filename); - g_free (filename); - - /* Load and initialize gimp modules */ - - modules = gimp_list_new (GIMP_TYPE_MODULE_INFO, GIMP_CONTAINER_POLICY_WEAK); - - if (g_module_supported ()) - gimp_datafiles_read_directories (the_gimp->config->module_path, 0 /* no flags */, - module_initialize, NULL); -#ifdef DUMP_DB - gimp_container_foreach (modules, print_module_info, NULL); -#endif -} - -static void -free_a_single_module (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - - if (mod->module && mod->unload && mod->state == ST_LOADED_OK) - { - mod_unload (mod, FALSE); - } -} - -static void -add_to_inhibit_string (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - GString *str = user_data; - - if (mod->load_inhibit) - { - str = g_string_append_c (str, G_SEARCHPATH_SEPARATOR); - str = g_string_append (str, mod->fullpath); - } -} - - -static gboolean -module_db_write_modulerc (void) -{ - GString *str; - gchar *p; - gchar *filename; - FILE *fp; - gboolean saved = FALSE; - - str = g_string_new (NULL); - gimp_container_foreach (modules, add_to_inhibit_string, str); - if (str->len > 0) - p = str->str + 1; - else - p = ""; - - filename = gimp_personal_rc_file ("modulerc"); - fp = fopen (filename, "wt"); - g_free (filename); - if (fp) - { - fprintf (fp, "(module-load-inhibit \"%s\")\n", p); - fclose (fp); - saved = TRUE; - } - - g_string_free (str, TRUE); - return (saved); -} - - -void -module_db_free (void) -{ - if (need_to_rewrite_modulerc) - { - if (module_db_write_modulerc ()) - { - need_to_rewrite_modulerc = FALSE; - } - } - gimp_container_foreach (modules, free_a_single_module, NULL); -} - - -GtkWidget * -module_db_browser_new (void) -{ - GtkWidget *shell; - GtkWidget *hbox; - GtkWidget *vbox; - GtkWidget *listbox; - GtkWidget *button; - BrowserState *st; - - shell = gimp_dialog_new (_("Module DB"), "module_db_dialog", - gimp_standard_help_func, - "dialogs/module_browser.html", - GTK_WIN_POS_NONE, - FALSE, TRUE, FALSE, - - GTK_STOCK_OK, browser_popdown_callback, - NULL, NULL, NULL, TRUE, TRUE, - - NULL); - - vbox = gtk_vbox_new (FALSE, 5); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (shell)->vbox), vbox); - gtk_widget_show (vbox); - - listbox = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (listbox), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_box_pack_start (GTK_BOX (vbox), listbox, TRUE, TRUE, 0); - gtk_widget_set_usize (listbox, 125, 100); - gtk_widget_show (listbox); - - st = g_new0 (BrowserState, 1); - - st->list = gtk_list_new (); - gtk_list_set_selection_mode (GTK_LIST (st->list), GTK_SELECTION_BROWSE); - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox), - st->list); - - gimp_container_foreach (modules, make_list_item, st); - - gtk_widget_show (st->list); - - st->table = gtk_table_new (5, NUM_INFO_LINES + 1, FALSE); - gtk_table_set_col_spacings (GTK_TABLE (st->table), 4); - gtk_box_pack_start (GTK_BOX (vbox), st->table, FALSE, FALSE, 0); - gtk_widget_show (st->table); - - hbox = gtk_hbutton_box_new (); - gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD); - - gtk_widget_show (hbox); - gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 5); - - button = gtk_button_new_with_label (_("Refresh")); - gtk_widget_show (button); - g_signal_connect (G_OBJECT (button), "clicked", - G_CALLBACK (browser_refresh_callback), st); - gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); - - st->button = gtk_button_new_with_label (""); - st->button_label = GTK_BIN (st->button)->child; - gtk_box_pack_start (GTK_BOX (hbox), st->button, TRUE, TRUE, 0); - gtk_widget_show (st->button); - g_signal_connect (G_OBJECT (st->button), "clicked", - G_CALLBACK (browser_load_unload_callback), st); - - browser_info_init (st, st->table); - browser_info_update (st->last_update, st); - - g_object_set_data (G_OBJECT (st->list), "state", st); - - g_signal_connect (G_OBJECT (st->list), "select_child", - G_CALLBACK (browser_select_callback), NULL); - - /* hook the GimpContainer signals so we can refresh the display - * appropriately. - */ - modules_handler_id = - gimp_container_add_handler (modules, "modified", - G_CALLBACK (browser_info_update), st); - - g_signal_connect (G_OBJECT (modules), "add", - G_CALLBACK (browser_info_add), - st); - g_signal_connect (G_OBJECT (modules), "remove", - G_CALLBACK (browser_info_remove), - st); - - g_signal_connect (G_OBJECT (shell), "destroy", - G_CALLBACK (browser_destroy_callback), - st); - - return shell; -} - - - -/**************************************************************/ -/* helper functions */ - - -/* name must be of the form lib*.so (Unix) or *.dll (Win32) */ -static gboolean -valid_module_name (const gchar *filename) -{ - gchar *basename; - gint len; - - basename = g_path_get_basename (filename); - - len = strlen (basename); - -#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) && !defined(__EMX__) - if (len < 3 + 1 + 3) - goto no_module; - - if (strncmp (basename, "lib", 3)) - goto no_module; - - if (strcmp (basename + len - 3, ".so")) - goto no_module; -#else - if (len < 1 + 4) - goto no_module; - - if (g_strcasecmp (basename + len - 4, ".dll")) - goto no_module; -#endif - - g_free (basename); - - return TRUE; - - no_module: - g_free (basename); - - return FALSE; -} - - -static gboolean -module_inhibited (const gchar *fullpath, - const gchar *inhibit_list) -{ - gchar *p; - gint pathlen; - const gchar *start; - const gchar *end; - - /* common case optimisation: the list is empty */ - if (!inhibit_list || *inhibit_list == '\000') - return FALSE; - - p = strstr (inhibit_list, fullpath); - 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 (fullpath); - if ((end - start) == pathlen) - return TRUE; - else - return FALSE; -} - - -static void -module_initialize (const gchar *filename, - gpointer loader_data) -{ - GimpModuleInfoObj *mod; - - if (!valid_module_name (filename)) - return; - - /* don't load if we already know about it */ - if (module_find_by_path (filename)) - return; - - mod = gimp_module_info_new (); - - mod->fullpath = g_strdup (filename); - mod->ondisk = TRUE; - mod->state = ST_MODULE_ERROR; - - mod->info = NULL; - mod->module = NULL; - mod->last_module_error = NULL; - mod->init = NULL; - mod->unload = NULL; - - /* Count of times main gimp is within the module. Normally, this - * will be 1, and we assume that the module won't call its - * unload callback until it is satisfied that it's not in use any - * more. refs can be 2 temporarily while we're running the module's - * unload function, to stop the module attempting to unload - * itself. - */ - mod->refs = 0; - - mod->load_inhibit = module_inhibited (mod->fullpath, - the_gimp->config->module_db_load_inhibit); - if (!mod->load_inhibit) - { - if (be_verbose) - g_print (_("load module: \"%s\"\n"), filename); - - mod_load (mod, TRUE); - } - else - { - if (be_verbose) - g_print (_("skipping module: \"%s\"\n"), filename); - - mod->state = ST_UNLOADED_OK; - } - - gimp_container_add (modules, GIMP_OBJECT (mod)); -} - -static void -mod_load (GimpModuleInfoObj *mod, - gboolean verbose) -{ - gpointer symbol; - - g_return_if_fail (mod->module == NULL); - - mod->module = g_module_open (mod->fullpath, G_MODULE_BIND_LAZY); - if (!mod->module) - { - mod->state = ST_MODULE_ERROR; - - if (mod->last_module_error) - g_free (mod->last_module_error); - mod->last_module_error = g_strdup (g_module_error ()); - - if (verbose) - g_warning (_("module load error: %s: %s"), - mod->fullpath, mod->last_module_error); - return; - } - -#ifdef __EMX__ - if (g_module_symbol (mod->module, "gimp_main_funcs", &symbol)) - { - *(struct main_funcs_struc **) symbol = gimp_main_funcs; - } -#endif - /* find the module_init symbol */ - if (!g_module_symbol (mod->module, "module_init", &symbol)) - { - mod->state = ST_MODULE_ERROR; - - if (mod->last_module_error) - g_free (mod->last_module_error); - mod->last_module_error = g_strdup ("missing module_init() symbol"); - - if (verbose) - g_warning ("%s: module_init() symbol not found", mod->fullpath); - - g_module_close (mod->module); - mod->module = NULL; - mod->info = NULL; - return; - } - - /* run module's initialisation */ - mod->init = symbol; - mod->info = NULL; - gimp_module_ref (mod); /* loaded modules are assumed to have a ref of 1 */ - if (mod->init (&mod->info) == GIMP_MODULE_UNLOAD) - { - mod->state = ST_LOAD_FAILED; - gimp_module_unref (mod); - mod->info = NULL; - return; - } - - /* module is now happy */ - mod->state = ST_LOADED_OK; - TRC (("loaded module %s, state at %p\n", mod->fullpath, mod)); - - /* do we have an unload function? */ - if (g_module_symbol (mod->module, "module_unload", &symbol)) - mod->unload = symbol; - else - mod->unload = NULL; -} - - -static void -mod_unload_completed_callback (gpointer data) -{ - GimpModuleInfoObj *mod = data; - - g_return_if_fail (mod->state == ST_UNLOAD_REQUESTED); - - /* lose the ref we gave this module when we loaded it, - * since the module's now happy to be unloaded. */ - gimp_module_unref (mod); - mod->info = NULL; - - mod->state = ST_UNLOADED_OK; - - TRC (("module unload completed callback for %p\n", mod)); - - gimp_module_info_modified (mod); -} - -static void -mod_unload (GimpModuleInfoObj *mod, - gboolean verbose) -{ - g_return_if_fail (mod->module != NULL); - g_return_if_fail (mod->unload != NULL); - - if (mod->state == ST_UNLOAD_REQUESTED) - return; - - mod->state = ST_UNLOAD_REQUESTED; - - TRC (("module unload requested for %p\n", mod)); - - /* 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_ref (mod); - mod->unload (mod->info->shutdown_data, mod_unload_completed_callback, mod); - - gtk_idle_add ((GtkFunction) mod_idle_unref, (gpointer) mod); -} - -static gboolean -mod_idle_unref (GimpModuleInfoObj *mod) -{ - gimp_module_unref (mod); - - return FALSE; -} - -#ifdef DUMP_DB -static void -print_module_info (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *i = data; - - g_print ("\n%s: %s\n", - i->fullpath, statename[i->state]); - g_print (" module:%p lasterr:%s init:%p unload:%p\n", - i->module, i->last_module_error? i->last_module_error : "NONE", - i->init, i->unload); - if (i->info) - { - g_print (" shutdown_data: %p\n" - " purpose: %s\n" - " author: %s\n" - " version: %s\n" - " copyright: %s\n" - " date: %s\n", - i->info->shutdown_data, - i->info->purpose, i->info->author, i->info->version, - i->info->copyright, i->info->date); - } -} -#endif - - - -/**************************************************************/ -/* UI functions */ - -static void -browser_popdown_callback (GtkWidget *widget, - gpointer data) -{ - gtk_widget_destroy (GTK_WIDGET (data)); -} - -static void -browser_destroy_callback (GtkWidget *widget, - gpointer data) -{ - g_signal_handlers_disconnect_by_func (G_OBJECT (modules), - browser_info_add, - data); - g_signal_handlers_disconnect_by_func (G_OBJECT (modules), - browser_info_remove, - data); - gimp_container_remove_handler (modules, modules_handler_id); - g_free (data); -} - -static void -browser_load_inhibit_callback (GtkWidget *widget, - gpointer data) -{ - BrowserState *st = data; - gboolean new_value; - - g_return_if_fail (st->last_update != NULL); - - new_value = ! GTK_TOGGLE_BUTTON (widget)->active; - - if (new_value == st->last_update->load_inhibit) - return; - - st->last_update->load_inhibit = new_value; - gimp_module_info_modified (st->last_update); - - need_to_rewrite_modulerc = TRUE; -} - -static void -browser_info_update (GimpModuleInfoObj *mod, - BrowserState *st) -{ - gint i; - const gchar *text[NUM_INFO_LINES - 1]; - gchar *status; - - /* only update the info if we're actually showing it */ - if (mod != st->last_update) - return; - - if (!mod) - { - for (i=0; i < NUM_INFO_LINES; i++) - gtk_label_set_text (GTK_LABEL (st->label[i]), ""); - gtk_label_set_text (GTK_LABEL(st->button_label), _("")); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); - gtk_widget_set_sensitive (GTK_WIDGET (st->load_inhibit_check), FALSE); - return; - } - - if (mod->info) - { - text[0] = mod->info->purpose; - text[1] = mod->info->author; - text[2] = mod->info->version; - text[3] = mod->info->copyright; - text[4] = mod->info->date; - text[5] = mod->ondisk? _("on disk") : _("only in memory"); - } - else - { - text[0] = "--"; - text[1] = "--"; - text[2] = "--"; - text[3] = "--"; - text[4] = "--"; - text[5] = mod->ondisk? _("on disk") : _("nowhere (click 'refresh')"); - } - - if (mod->state == ST_MODULE_ERROR && mod->last_module_error) - status = g_strdup_printf ("%s (%s)", gettext (statename[mod->state]), - mod->last_module_error); - else - { - status = g_strdup (gettext (statename[mod->state])); - } - - for (i=0; i < NUM_INFO_LINES - 1; i++) - { - gtk_label_set_text (GTK_LABEL (st->label[i]), gettext (text[i])); - } - - gtk_label_set_text (GTK_LABEL (st->label[NUM_INFO_LINES-1]), status); - - g_free (status); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (st->load_inhibit_check), - !mod->load_inhibit); - gtk_widget_set_sensitive (GTK_WIDGET (st->load_inhibit_check), TRUE); - - /* work out what the button should do (if anything) */ - switch (mod->state) - { - case ST_MODULE_ERROR: - case ST_LOAD_FAILED: - case ST_UNLOADED_OK: - gtk_label_set_text (GTK_LABEL(st->button_label), _("Load")); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->ondisk); - break; - - case ST_UNLOAD_REQUESTED: - gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE); - break; - - case ST_LOADED_OK: - gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload")); - gtk_widget_set_sensitive (GTK_WIDGET (st->button), - mod->unload? TRUE : FALSE); - break; - } -} - -static void -browser_info_init (BrowserState *st, - GtkWidget *table) -{ - GtkWidget *label; - gint i; - - gchar *text[] = - { - N_("Purpose:"), - N_("Author:"), - N_("Version:"), - N_("Copyright:"), - N_("Date:"), - N_("Location:"), - N_("State:") - }; - - for (i=0; i < sizeof(text) / sizeof(char *); i++) - { - label = gtk_label_new (gettext (text[i])); - gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); - gtk_widget_show (label); - - st->label[i] = gtk_label_new (""); - gtk_misc_set_alignment (GTK_MISC (st->label[i]), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (st->table), st->label[i], 1, 2, i, i+1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); - gtk_widget_show (st->label[i]); - } - - st->load_inhibit_check = - gtk_check_button_new_with_label (_("Autoload during startup")); - gtk_widget_show (st->load_inhibit_check); - gtk_table_attach (GTK_TABLE (table), st->load_inhibit_check, - 0, 2, i, i+1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2); - g_signal_connect (G_OBJECT (st->load_inhibit_check), "toggled", - G_CALLBACK (browser_load_inhibit_callback), st); -} - -static void -browser_select_callback (GtkWidget *widget, - GtkWidget *child) -{ - GimpModuleInfoObj *info; - BrowserState *st; - - info = g_object_get_data (G_OBJECT (child), "module_info"); - st = g_object_get_data (G_OBJECT (widget), "state"); - - if (st->last_update == info) - return; - - st->last_update = info; - - browser_info_update (st->last_update, st); -} - - -static void -browser_load_unload_callback (GtkWidget *widget, - gpointer data) -{ - BrowserState *st = data; - - if (st->last_update->state == ST_LOADED_OK) - mod_unload (st->last_update, FALSE); - else - mod_load (st->last_update, FALSE); - - gimp_module_info_modified (st->last_update); -} - - -static void -make_list_item (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *info = data; - BrowserState *st = user_data; - GtkWidget *list_item; - - if (!st->last_update) - st->last_update = info; - - list_item = gtk_list_item_new_with_label (info->fullpath); - - gtk_widget_show (list_item); - g_object_set_data (G_OBJECT (list_item), "module_info", info); - - gtk_container_add (GTK_CONTAINER (st->list), list_item); -} - - -static void -browser_info_add (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st) -{ - make_list_item (mod, st); -} - - -static void -browser_info_remove (GimpContainer *container, - GimpModuleInfoObj *mod, - BrowserState *st) -{ - GList *dlist; - GList *free_list; - GtkWidget *list_item; - GimpModuleInfoObj *info; - - dlist = gtk_container_get_children (GTK_CONTAINER (st->list)); - free_list = dlist; - - while (dlist) - { - list_item = dlist->data; - - info = g_object_get_data (G_OBJECT (list_item), "module_info"); - g_return_if_fail (info != NULL); - - if (info == mod) - { - gtk_container_remove (GTK_CONTAINER (st->list), list_item); - g_list_free (free_list); - return; - } - - dlist = dlist->next; - } - - g_warning ("tried to remove module that wasn't in brower's list"); - g_list_free (free_list); -} - - - -static void -module_db_module_ondisk (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - struct stat statbuf; - gint ret; - gint old_ondisk = mod->ondisk; - GSList **kill_list = user_data; - - ret = stat (mod->fullpath, &statbuf); - if (ret != 0) - mod->ondisk = FALSE; - else - mod->ondisk = TRUE; - - /* if it's not on the disk, and it isn't in memory, mark it to be - * removed later. */ - if (!mod->ondisk && !mod->module) - { - *kill_list = g_slist_append (*kill_list, mod); - mod = NULL; - } - - if (mod && mod->ondisk != old_ondisk) - gimp_module_info_modified (mod); -} - - -static void -module_db_module_remove (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - - gimp_container_remove (modules, GIMP_OBJECT (mod)); - - g_object_unref (G_OBJECT (mod)); -} - - - -typedef struct -{ - const gchar *search_key; - GimpModuleInfoObj *found; -} find_by_path_closure; - -static void -module_db_path_cmp (gpointer data, - gpointer user_data) -{ - GimpModuleInfoObj *mod = data; - find_by_path_closure *cl = user_data; - - if (!strcmp (mod->fullpath, cl->search_key)) - cl->found = mod; -} - -static GimpModuleInfoObj * -module_find_by_path (const char *fullpath) -{ - find_by_path_closure cl; - - cl.found = NULL; - cl.search_key = fullpath; - - gimp_container_foreach (modules, module_db_path_cmp, &cl); - - return cl.found; -} - - - -static void -browser_refresh_callback (GtkWidget *widget, - gpointer data) -{ - GSList *kill_list = NULL; - - /* remove modules we don't have on disk anymore */ - gimp_container_foreach (modules, module_db_module_ondisk, &kill_list); - g_slist_foreach (kill_list, module_db_module_remove, NULL); - g_slist_free (kill_list); - kill_list = NULL; - - /* walk filesystem and add new things we find */ - gimp_datafiles_read_directories (the_gimp->config->module_path, 0 /* no flags */, - module_initialize, NULL); -} - - -static void -gimp_module_ref (GimpModuleInfoObj *mod) -{ - g_return_if_fail (mod->refs >= 0); - g_return_if_fail (mod->module != NULL); - mod->refs++; -} - -static void -gimp_module_unref (GimpModuleInfoObj *mod) -{ - g_return_if_fail (mod->refs > 0); - g_return_if_fail (mod->module != NULL); - - mod->refs--; - - if (mod->refs == 0) - { - TRC (("module %p refs hit 0, g_module_closing it\n", mod)); - g_module_close (mod->module); - mod->module = NULL; - } -} diff --git a/app/xcf/xcf.c b/app/xcf/xcf.c index 37aa207ced..3123df011e 100644 --- a/app/xcf/xcf.c +++ b/app/xcf/xcf.c @@ -158,6 +158,8 @@ static gint n_xcf_loaders = sizeof (xcf_loaders) / sizeof (xcf_loaders[0]); void xcf_init (Gimp *gimp) { + g_return_if_fail (GIMP_IS_GIMP (gimp)); + /* So this is sort of a hack, but its better than it was before. To do this * right there would be a file load-save handler type and the whole interface * would change but there isn't, and currently the plug-in structure contains @@ -178,8 +180,9 @@ xcf_init (Gimp *gimp) } void -xcf_exit (void) +xcf_exit (Gimp *gimp) { + g_return_if_fail (GIMP_IS_GIMP (gimp)); } static Argument* diff --git a/app/xcf/xcf.h b/app/xcf/xcf.h index 23bd9b5475..2f6f1140a6 100644 --- a/app/xcf/xcf.h +++ b/app/xcf/xcf.h @@ -21,7 +21,7 @@ void xcf_init (Gimp *gimp); -void xcf_exit (void); +void xcf_exit (Gimp *gimp); #endif /* __XCF_H__ */ diff --git a/libgimpmodule/gimpmodule.c b/libgimpmodule/gimpmodule.c new file mode 100644 index 0000000000..3ee46f4126 --- /dev/null +++ b/libgimpmodule/gimpmodule.c @@ -0,0 +1,400 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmoduleinfo.c + * (C) 1999 Austin Donnelly + * + * 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 + +#include + +#include "libgimp/gimpmodule.h" + +#include "core-types.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 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; + + object_class = G_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, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->finalize = gimp_module_info_finalize; + + 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); +} + +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_warning (_("module load error: %s: %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_warning ("%s: module_init() symbol not found", + module_info->fullpath); + + 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; + } +} diff --git a/libgimpmodule/gimpmodule.h b/libgimpmodule/gimpmodule.h new file mode 100644 index 0000000000..fab3884f53 --- /dev/null +++ b/libgimpmodule/gimpmodule.h @@ -0,0 +1,102 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmoduleinfo.h + * (C) 1999 Austin Donnelly + * + * 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. + */ + +#ifndef __GIMP_MODULE_INFO_H__ +#define __GIMP_MODULE_INFO_H__ + + +#include "libgimp/gimpmodule.h" + +#include "gimpobject.h" + + +typedef enum +{ + GIMP_MODULE_STATE_ERROR, /* missing module_load function or other error */ + GIMP_MODULE_STATE_LOADED_OK, /* happy and running (normal state of affairs) */ + GIMP_MODULE_STATE_LOAD_FAILED, /* module_load returned GIMP_MODULE_UNLOAD */ + GIMP_MODULE_STATE_UNLOAD_REQUESTED, /* sent unload request, waiting for callback */ + GIMP_MODULE_STATE_UNLOADED_OK /* callback arrived, module not in memory anymore */ +} GimpModuleState; + + +#define GIMP_TYPE_MODULE_INFO (gimp_module_info_get_type ()) +#define GIMP_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObj)) +#define GIMP_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) +#define GIMP_IS_MODULE_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_MODULE_INFO)) +#define GIMP_IS_MODULE_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_MODULE_INFO)) +#define GIMP_MODULE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_MODULE_INFO, GimpModuleInfoObjClass)) + + +typedef struct _GimpModuleInfoObjClass GimpModuleInfoObjClass; + +struct _GimpModuleInfoObj +{ + GimpObject parent_instance; + + gchar *fullpath; /* path to the module */ + GimpModuleState state; /* what's happened to the module */ + gboolean on_disk; /* TRUE if file still exists */ + gboolean load_inhibit; /* user requests not to load at boot time */ + + /* Count of times main gimp is within the module. Normally, this + * will be 1, and we assume that the module won't call its + * unload callback until it is satisfied that it's not in use any + * more. refs can be 2 temporarily while we're running the module's + * unload function, to stop the module attempting to unload + * itself. + */ + gint refs; + + /* stuff from now on may be NULL depending on the state the module is in */ + GimpModuleInfo *info; /* returned values from module_init */ + GModule *module; /* handle on the module */ + gchar *last_module_error; + + GimpModuleInitFunc init; + GimpModuleUnloadFunc unload; +}; + +struct _GimpModuleInfoObjClass +{ + GimpObjectClass parent_class; + + void (* modified) (GimpModuleInfoObj *module_info); +}; + + +GType gimp_module_info_get_type (void); + +GimpModuleInfoObj * gimp_module_info_new (const gchar *filename); + +void gimp_module_info_modified (GimpModuleInfoObj *module); +void gimp_module_info_set_load_inhibit (GimpModuleInfoObj *module, + const gchar *inhibit_list); + +void gimp_module_info_module_load (GimpModuleInfoObj *module_info, + gboolean verbose); +void gimp_module_info_module_unload (GimpModuleInfoObj *module_info, + gboolean verbose); +void gimp_module_info_module_ref (GimpModuleInfoObj *module_info); +void gimp_module_info_module_unref (GimpModuleInfoObj *module_info); + + +#endif /* __GIMP_MODULE_INFO_H__ */ diff --git a/libgimpmodule/gimpmoduledb.c b/libgimpmodule/gimpmoduledb.c new file mode 100644 index 0000000000..33eb5a35c7 --- /dev/null +++ b/libgimpmodule/gimpmoduledb.c @@ -0,0 +1,400 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmodules.c + * (C) 1999 Austin Donnelly + * + * 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 +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include + +#include "libgimpbase/gimpbase.h" + +#include "core-types.h" + +#include "core/gimp.h" +#include "core/gimpcoreconfig.h" +#include "core/gimpdatafiles.h" +#include "core/gimplist.h" +#include "core/gimpmoduleinfo.h" +#include "core/gimpmodules.h" + +#include "gimprc.h" + +#include "libgimp/gimpintl.h" + + +static void gimp_modules_module_initialize (const gchar *filename, + gpointer loader_data); + +static GimpModuleInfoObj * gimp_modules_module_find_by_path (Gimp *gimp, + const char *fullpath); + +#ifdef DUMP_DB +static void print_module_info (gpointer data, + gpointer user_data); +#endif + +static gboolean gimp_modules_write_modulerc (Gimp *gimp); + +static void gimp_modules_module_free_func (gpointer data, + gpointer user_data); +static void gimp_modules_module_on_disk_func (gpointer data, + gpointer user_data); +static void gimp_modules_module_remove_func (gpointer data, + gpointer user_data); + + +void +gimp_modules_init (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + gimp->modules = gimp_list_new (GIMP_TYPE_MODULE_INFO, + GIMP_CONTAINER_POLICY_STRONG); + gimp->write_modulerc = FALSE; +} + +void +gimp_modules_exit (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + if (gimp->modules) + { + g_object_unref (G_OBJECT (gimp->modules)); + gimp->modules = NULL; + } +} + +void +gimp_modules_load (Gimp *gimp) +{ + gchar *filename; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + filename = gimp_personal_rc_file ("modulerc"); + gimprc_parse_file (filename); + g_free (filename); + + if (g_module_supported ()) + gimp_datafiles_read_directories (gimp->config->module_path, + 0 /* no flags */, + gimp_modules_module_initialize, + gimp); + +#ifdef DUMP_DB + gimp_container_foreach (modules, print_module_info, NULL); +#endif +} + +void +gimp_modules_unload (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + if (gimp->write_modulerc) + { + if (gimp_modules_write_modulerc (gimp)) + { + gimp->write_modulerc = FALSE; + } + } + + gimp_container_foreach (gimp->modules, gimp_modules_module_free_func, NULL); +} + +void +gimp_modules_refresh (Gimp *gimp) +{ + GList *kill_list = NULL; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + /* remove modules we don't have on disk anymore */ + gimp_container_foreach (gimp->modules, + gimp_modules_module_on_disk_func, + &kill_list); + g_list_foreach (kill_list, + gimp_modules_module_remove_func, + gimp); + g_list_free (kill_list); + + /* walk filesystem and add new things we find */ + gimp_datafiles_read_directories (gimp->config->module_path, + 0 /* no flags */, + gimp_modules_module_initialize, + gimp); +} + +static void +gimp_modules_module_free_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info = data; + + if (module_info->module && + module_info->unload && + module_info->state == GIMP_MODULE_STATE_LOADED_OK) + { + gimp_module_info_module_unload (module_info, FALSE); + } +} + +static void +add_to_inhibit_string (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info = data; + GString *str = user_data; + + if (module_info->load_inhibit) + { + str = g_string_append_c (str, G_SEARCHPATH_SEPARATOR); + str = g_string_append (str, module_info->fullpath); + } +} + +static gboolean +gimp_modules_write_modulerc (Gimp *gimp) +{ + GString *str; + gchar *p; + gchar *filename; + FILE *fp; + gboolean saved = FALSE; + + str = g_string_new (NULL); + gimp_container_foreach (gimp->modules, add_to_inhibit_string, str); + if (str->len > 0) + p = str->str + 1; + else + p = ""; + + filename = gimp_personal_rc_file ("modulerc"); + fp = fopen (filename, "wt"); + g_free (filename); + if (fp) + { + fprintf (fp, "(module-load-inhibit \"%s\")\n", p); + fclose (fp); + saved = TRUE; + } + + g_string_free (str, TRUE); + + return saved; +} + +/* name must be of the form lib*.so (Unix) or *.dll (Win32) */ +static gboolean +valid_module_name (const gchar *filename) +{ + gchar *basename; + gint len; + + basename = g_path_get_basename (filename); + + len = strlen (basename); + +#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) && !defined(__EMX__) + if (len < 3 + 1 + 3) + goto no_module; + + if (strncmp (basename, "lib", 3)) + goto no_module; + + if (strcmp (basename + len - 3, ".so")) + goto no_module; +#else + if (len < 1 + 4) + goto no_module; + + if (g_strcasecmp (basename + len - 4, ".dll")) + goto no_module; +#endif + + g_free (basename); + + return TRUE; + + no_module: + g_free (basename); + + return FALSE; +} + +static void +gimp_modules_module_initialize (const gchar *filename, + gpointer loader_data) +{ + GimpModuleInfoObj *module_info; + Gimp *gimp; + + gimp = GIMP (loader_data); + + if (! valid_module_name (filename)) + return; + + /* don't load if we already know about it */ + if (gimp_modules_module_find_by_path (gimp, filename)) + return; + + module_info = gimp_module_info_new (filename); + + gimp_module_info_set_load_inhibit (module_info, + gimp->config->module_db_load_inhibit); + + if (! module_info->load_inhibit) + { + if (gimp->be_verbose) + g_print (_("load module: \"%s\"\n"), filename); + + gimp_module_info_module_load (module_info, TRUE); + } + else + { + if (gimp->be_verbose) + g_print (_("skipping module: \"%s\"\n"), filename); + + module_info->state = GIMP_MODULE_STATE_UNLOADED_OK; + } + + gimp_container_add (gimp->modules, GIMP_OBJECT (module_info)); + + g_object_unref (G_OBJECT (module_info)); +} + +typedef struct +{ + const gchar *search_key; + GimpModuleInfoObj *found; +} find_by_path_closure; + +static void +gimp_modules_module_path_cmp_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + find_by_path_closure *closure; + + module_info = (GimpModuleInfoObj *) data; + closure = (find_by_path_closure *) user_data; + + if (! strcmp (module_info->fullpath, closure->search_key)) + closure->found = module_info; +} + +static GimpModuleInfoObj * +gimp_modules_module_find_by_path (Gimp *gimp, + const char *fullpath) +{ + find_by_path_closure cl; + + cl.found = NULL; + cl.search_key = fullpath; + + gimp_container_foreach (gimp->modules, + gimp_modules_module_path_cmp_func, &cl); + + return cl.found; +} + +#ifdef DUMP_DB +static void +print_module_info (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *i = data; + + g_print ("\n%s: %s\n", + i->fullpath, statename[i->state]); + g_print (" module:%p lasterr:%s init:%p unload:%p\n", + i->module, i->last_module_error? i->last_module_error : "NONE", + i->init, i->unload); + if (i->info) + { + g_print (" shutdown_data: %p\n" + " purpose: %s\n" + " author: %s\n" + " version: %s\n" + " copyright: %s\n" + " date: %s\n", + i->info->shutdown_data, + i->info->purpose, i->info->author, i->info->version, + i->info->copyright, i->info->date); + } +} +#endif + +static void +gimp_modules_module_on_disk_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + GList **kill_list; + gint old_on_disk; + struct stat statbuf; + gint ret; + + module_info = (GimpModuleInfoObj *) data; + kill_list = (GList **) user_data; + + old_on_disk = module_info->on_disk; + + ret = stat (module_info->fullpath, &statbuf); + if (ret != 0) + module_info->on_disk = FALSE; + else + module_info->on_disk = TRUE; + + /* if it's not on the disk, and it isn't in memory, mark it to be + * removed later. + */ + if (! module_info->on_disk && ! module_info->module) + { + *kill_list = g_list_append (*kill_list, module_info); + module_info = NULL; + } + + if (module_info && module_info->on_disk != old_on_disk) + gimp_module_info_modified (module_info); +} + +static void +gimp_modules_module_remove_func (gpointer data, + gpointer user_data) +{ + GimpModuleInfoObj *module_info; + Gimp *gimp; + + module_info = (GimpModuleInfoObj *) data; + gimp = (Gimp *) user_data; + + gimp_container_remove (gimp->modules, GIMP_OBJECT (module_info)); +} diff --git a/libgimpmodule/gimpmoduledb.h b/libgimpmodule/gimpmoduledb.h new file mode 100644 index 0000000000..48aa49e665 --- /dev/null +++ b/libgimpmodule/gimpmoduledb.h @@ -0,0 +1,35 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpmodules.h + * (C) 1999 Austin Donnelly + * + * 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. + */ + +#ifndef __GIMP_MODULES_H__ +#define __GIMP_MODULES_H__ + + +void gimp_modules_init (Gimp *gimp); +void gimp_modules_exit (Gimp *gimp); + +void gimp_modules_load (Gimp *gimp); +void gimp_modules_unload (Gimp *gimp); + +void gimp_modules_refresh (Gimp *gimp); + + +#endif /* __GIMP_MODULES_H__ */ diff --git a/po/ChangeLog b/po/ChangeLog index fd0b7f3ac3..033381ae74 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,7 @@ +2001-10-18 Michael Natterer + + * POTFILES.in: module_db.c has moved. + 2001-10-09 Sven Neumann * Makefile.in.in: forgot to add this file which is needed now that diff --git a/po/POTFILES.in b/po/POTFILES.in index 161abe28d1..88c49c52ab 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,7 +12,6 @@ app/gimphelp.c app/gimpprogress.c app/gimprc.c app/main.c -app/module_db.c app/nav_window.c app/plug_in.c app/qmask.c @@ -67,6 +66,7 @@ app/gui/info-window.c app/gui/layer-select.c app/gui/layers-commands.c app/gui/menus.c +app/gui/module-browser.c app/gui/offset-dialog.c app/gui/palette-editor.c app/gui/palette-import-dialog.c