home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / module_db.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  28.4 KB  |  1,152 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * module_db.c (C) 1999 Austin Donnelly <austin@gimp.org>
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  */
  20.  
  21. #include "config.h"
  22.  
  23. #include <glib.h>
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #ifdef HAVE_UNISTD_H
  30. #include <unistd.h>
  31. #endif
  32. #include <time.h>
  33.  
  34. #include <gtk/gtk.h>
  35.  
  36. #include "apptypes.h"
  37.  
  38. #include "appenv.h"
  39. #include "module_db.h"
  40. #include "gimpsignal.h"
  41. #include "gimprc.h"
  42. #include "datafiles.h"
  43. #include "gimpset.h"
  44. #include "gimpui.h"
  45.  
  46. #include "libgimp/gimpenv.h"
  47. #include "libgimp/gimpmodule.h"
  48.  
  49. #include "libgimp/gimpintl.h"
  50.  
  51.  
  52. /* export this to gimprc.c */
  53. gchar *module_db_load_inhibit = NULL;
  54.  
  55. typedef enum
  56. {
  57.   ST_MODULE_ERROR,         /* missing module_load function or other error    */
  58.   ST_LOADED_OK,            /* happy and running (normal state of affairs)    */
  59.   ST_LOAD_FAILED,          /* module_load returned GIMP_MODULE_UNLOAD        */
  60.   ST_UNLOAD_REQUESTED,     /* sent unload request, waiting for callback      */
  61.   ST_UNLOADED_OK           /* callback arrived, module not in memory anymore */
  62. } module_state;
  63.  
  64. static const gchar * const statename[] =
  65. {
  66.   N_("Module error"),
  67.   N_("Loaded OK"),
  68.   N_("Load failed"),
  69.   N_("Unload requested"),
  70.   N_("Unloaded OK")
  71. };
  72.  
  73. #ifdef __EMX__
  74. extern void gimp_color_selector_register   ();
  75. extern void gimp_color_selector_unregister ();
  76. extern void gimp_color_display_register    ();
  77. extern void gimp_color_display_unregister  ();
  78. extern void dialog_register                ();
  79. extern void dialog_unregister              ();
  80.  
  81. static struct main_funcs_struc
  82. {
  83.   gchar *name;
  84.   void (*func) ();
  85.  
  86. gimp_main_funcs[] =
  87. {
  88.   { "gimp_color_selector_register",   gimp_color_selector_register },
  89.   { "gimp_color_selector_unregister", gimp_color_selector_unregister },
  90.   { "gimp_color_display_register",    gimp_color_display_register },
  91.   { "gimp_color_display_unregister",  gimp_color_display_unregister },
  92.   { "dialog_register",                dialog_register },
  93.   { "dialog_unregister",              dialog_unregister },
  94.   { NULL, NULL }
  95. };
  96. #endif
  97.  
  98.  
  99. /* one of these objects is kept per-module */
  100. typedef struct
  101. {
  102.   GtkObject       object;
  103.  
  104.   gchar          *fullpath;     /* path to the module                        */
  105.   module_state    state;        /* what's happened to the module             */
  106.   gboolean        ondisk;       /* TRUE if file still exists                 */
  107.   gboolean        load_inhibit; /* user requests not to load at boot time    */
  108.   gint            refs;         /* how many time we're running in the module */
  109.  
  110.   /* stuff from now on may be NULL depending on the state the module is in   */
  111.   GimpModuleInfo *info;         /* returned values from module_init          */
  112.   GModule        *module;       /* handle on the module                      */
  113.   gchar          *last_module_error;
  114.  
  115.   GimpModuleInitFunc   init;
  116.   GimpModuleUnloadFunc unload;
  117. } ModuleInfo;
  118.  
  119.  
  120. static guint module_info_get_type (void);
  121.  
  122. #define MODULE_INFO_TYPE    module_info_get_type()
  123. #define MODULE_INFO(obj)    GTK_CHECK_CAST (obj, MODULE_INFO_TYPE, ModuleInfo)
  124. #define IS_MODULE_INFO(obj) GTK_CHECK_TYPE (obj, MODULE_INFO_TYPE)
  125.  
  126.  
  127. #define NUM_INFO_LINES 7
  128.  
  129. typedef struct
  130. {
  131.   GtkWidget  *table;
  132.   GtkWidget  *label[NUM_INFO_LINES];
  133.   GtkWidget  *button_label;
  134.   ModuleInfo *last_update;
  135.   GtkWidget  *button;
  136.   GtkWidget  *list;
  137.   GtkWidget  *load_inhibit_check;
  138. } BrowserState;
  139.  
  140. /* global set of module_info pointers */
  141. static GimpSet          *modules;
  142. static GimpSetHandlerId  modules_handler;
  143.  
  144. /* If the inhibit state of any modules changes, we might need to
  145.  * re-write the modulerc. */
  146. static gboolean need_to_rewrite_modulerc = FALSE;
  147.  
  148.  
  149. /* debug control: */
  150.  
  151. /*#define DUMP_DB*/
  152. /*#define DEBUG*/
  153.  
  154. #ifdef DEBUG
  155. #undef DUMP_DB
  156. #define DUMP_DB
  157. #define TRC(x) printf x
  158. #else
  159. #define TRC(x)
  160. #endif
  161.  
  162.  
  163. /* prototypes */
  164. static void         module_initialize      (gchar        *filename);
  165. static void         mod_load               (ModuleInfo   *mod,
  166.                         gboolean      verbose);
  167. static void         mod_unload             (ModuleInfo   *mod,
  168.                         gboolean      verbose);
  169. static gboolean     mod_idle_unref         (ModuleInfo   *mod);
  170. static ModuleInfo * module_find_by_path    (const gchar  *fullpath);
  171.  
  172. #ifdef DUMP_DB
  173. static void   print_module_info            (gpointer      data,
  174.                         gpointer      user_data);
  175. #endif
  176.  
  177. static void   browser_popdown_callback     (GtkWidget    *widget,
  178.                         gpointer      data);
  179. static void   browser_destroy_callback     (GtkWidget    *widget,
  180.                         gpointer      data);
  181. static void   browser_info_update          (ModuleInfo   *mod,
  182.                         BrowserState *st);
  183. static void   browser_info_add             (GimpSet      *set,
  184.                         ModuleInfo   *mod,
  185.                         BrowserState *st);
  186. static void   browser_info_remove          (GimpSet      *set,
  187.                         ModuleInfo   *mod,
  188.                         BrowserState *st);
  189. static void   browser_info_init            (BrowserState *st,
  190.                         GtkWidget    *table);
  191. static void   browser_select_callback      (GtkWidget    *widget,
  192.                         GtkWidget    *child);
  193. static void   browser_load_unload_callback (GtkWidget    *widget,
  194.                         gpointer      data);
  195. static void   browser_refresh_callback     (GtkWidget    *widget,
  196.                         gpointer      data);
  197. static void   make_list_item               (gpointer      data,
  198.                         gpointer      user_data);
  199.  
  200. static void   gimp_module_ref              (ModuleInfo   *mod);
  201. static void   gimp_module_unref            (ModuleInfo   *mod);
  202.  
  203.  
  204.  
  205. /**************************************************************/
  206. /* Exported functions */
  207.  
  208. void
  209. module_db_init (void)
  210. {
  211.   gchar *filename;
  212.  
  213.   /* load the modulerc file */
  214.   filename = gimp_personal_rc_file ("modulerc");
  215.   parse_gimprc_file (filename);
  216.   g_free (filename);
  217.  
  218.   /* Load and initialize gimp modules */
  219.  
  220.   modules = gimp_set_new (MODULE_INFO_TYPE, FALSE);
  221.  
  222.   if (g_module_supported ())
  223.     datafiles_read_directories (module_path,
  224.                 module_initialize, 0 /* no flags */);
  225. #ifdef DUMP_DB
  226.   gimp_set_foreach (modules, print_module_info, NULL);
  227. #endif
  228. }
  229.  
  230. static void
  231. free_a_single_module (gpointer data, 
  232.               gpointer user_data)
  233. {
  234.   ModuleInfo *mod = data;
  235.  
  236.   if (mod->module && mod->unload && mod->state == ST_LOADED_OK)
  237.     {
  238.       mod_unload (mod, FALSE);
  239.     }
  240. }
  241.  
  242. static void
  243. add_to_inhibit_string (gpointer data, 
  244.                gpointer user_data)
  245. {
  246.   ModuleInfo *mod = data;
  247.   GString    *str = user_data;
  248.  
  249.   if (mod->load_inhibit)
  250.     {
  251.       str = g_string_append_c (str, G_SEARCHPATH_SEPARATOR);
  252.       str = g_string_append (str, mod->fullpath);
  253.     }
  254. }
  255.  
  256.  
  257. static gboolean
  258. module_db_write_modulerc (void)
  259. {
  260.   GString  *str;
  261.   gchar    *p;
  262.   gchar    *filename;
  263.   FILE     *fp;
  264.   gboolean  saved = FALSE;
  265.  
  266.   str = g_string_new (NULL);
  267.   gimp_set_foreach (modules, add_to_inhibit_string, str);
  268.   if (str->len > 0)
  269.     p = str->str + 1;
  270.   else
  271.     p = "";
  272.  
  273.   filename = gimp_personal_rc_file ("modulerc");
  274.   fp = fopen (filename, "wt");
  275.   g_free (filename);
  276.   if (fp)
  277.     {
  278.       fprintf (fp, "(module-load-inhibit \"%s\")\n", p);
  279.       fclose (fp);
  280.       saved = TRUE;
  281.     }
  282.  
  283.   g_string_free (str, TRUE);
  284.   return (saved);
  285. }
  286.  
  287.  
  288. void
  289. module_db_free (void)
  290. {
  291.   if (need_to_rewrite_modulerc)
  292.     {
  293.       if (module_db_write_modulerc ())
  294.     {
  295.       need_to_rewrite_modulerc = FALSE;
  296.     }
  297.     }
  298.   gimp_set_foreach (modules, free_a_single_module, NULL);
  299. }
  300.  
  301.  
  302. GtkWidget *
  303. module_db_browser_new (void)
  304. {
  305.   GtkWidget *shell;
  306.   GtkWidget *hbox;
  307.   GtkWidget *vbox;
  308.   GtkWidget *listbox;
  309.   GtkWidget *button;
  310.   BrowserState *st;
  311.  
  312.   shell = gimp_dialog_new (_("Module DB"), "module_db_dialog",
  313.                gimp_standard_help_func,
  314.                "dialogs/module_browser.html",
  315.                GTK_WIN_POS_NONE,
  316.                FALSE, TRUE, FALSE,
  317.  
  318.                _("OK"), browser_popdown_callback,
  319.                NULL, NULL, NULL, TRUE, TRUE,
  320.  
  321.                NULL);
  322.  
  323.   vbox = gtk_vbox_new (FALSE, 5);
  324.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
  325.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (shell)->vbox), vbox);
  326.   gtk_widget_show (vbox);
  327.  
  328.   listbox = gtk_scrolled_window_new (NULL, NULL);
  329.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (listbox),
  330.                   GTK_POLICY_AUTOMATIC,
  331.                   GTK_POLICY_AUTOMATIC);
  332.   gtk_box_pack_start (GTK_BOX (vbox), listbox, TRUE, TRUE, 0);
  333.   gtk_widget_set_usize (listbox, 125, 100);
  334.   gtk_widget_show (listbox);
  335.  
  336.   st = g_new0 (BrowserState, 1);
  337.  
  338.   st->list = gtk_list_new ();
  339.   gtk_list_set_selection_mode (GTK_LIST (st->list), GTK_SELECTION_BROWSE);
  340.   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (listbox),
  341.                      st->list);
  342.  
  343.   gimp_set_foreach (modules, make_list_item, st);
  344.  
  345.   gtk_widget_show (st->list);
  346.  
  347.   st->table = gtk_table_new (5, NUM_INFO_LINES + 1, FALSE);
  348.   gtk_table_set_col_spacings (GTK_TABLE (st->table), 4);  
  349.   gtk_box_pack_start (GTK_BOX (vbox), st->table, FALSE, FALSE, 0);
  350.   gtk_widget_show (st->table);
  351.  
  352.   hbox = gtk_hbutton_box_new ();
  353.   gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD);
  354.  
  355.   gtk_widget_show (hbox);
  356.   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 5);
  357.  
  358.   button = gtk_button_new_with_label (_("Refresh"));
  359.   gtk_widget_show (button);
  360.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  361.               browser_refresh_callback, st);
  362.   gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
  363.  
  364.   st->button = gtk_button_new_with_label ("");
  365.   st->button_label = GTK_BIN (st->button)->child;
  366.   gtk_box_pack_start (GTK_BOX (hbox), st->button, TRUE, TRUE, 0);
  367.   gtk_widget_show (st->button);
  368.   gtk_signal_connect (GTK_OBJECT (st->button), "clicked",
  369.               browser_load_unload_callback, st);
  370.  
  371.   browser_info_init (st, st->table);
  372.   browser_info_update (st->last_update, st);
  373.  
  374.   gtk_object_set_user_data (GTK_OBJECT (st->list), st);
  375.  
  376.   gtk_signal_connect (GTK_OBJECT (st->list), "select_child",
  377.               browser_select_callback, NULL);
  378.  
  379.   /* hook the gimpset signals so we can refresh the display
  380.    * appropriately. */
  381.   modules_handler =
  382.     gimp_set_add_handler (modules, "modified", browser_info_update, st);
  383.  
  384.   gtk_signal_connect (GTK_OBJECT (modules), "add", 
  385.               browser_info_add, st);
  386.   gtk_signal_connect (GTK_OBJECT (modules), "remove", 
  387.               browser_info_remove, st);
  388.  
  389.   gtk_signal_connect (GTK_OBJECT (shell), "destroy",
  390.               browser_destroy_callback, st);
  391.  
  392.   return shell;
  393. }
  394.  
  395.  
  396. /**************************************************************/
  397. /* ModuleInfo object glue */
  398.  
  399.  
  400. typedef struct
  401. {
  402.   GtkObjectClass parent_class;
  403. } ModuleInfoClass;
  404.  
  405. enum
  406. {
  407.   MODIFIED,
  408.   LAST_SIGNAL
  409. };
  410. static guint module_info_signals[LAST_SIGNAL];
  411.  
  412.  
  413. static void
  414. module_info_destroy (GtkObject *object)
  415. {
  416.   ModuleInfo *mod = MODULE_INFO (object);
  417.  
  418.   /* if this trips, then we're onto some serious lossage in a moment */
  419.   g_return_if_fail (mod->refs == 0);
  420.  
  421.   if (mod->last_module_error)
  422.     g_free (mod->last_module_error);
  423.   g_free (mod->fullpath);
  424. }
  425.  
  426. static void
  427. module_info_class_init (ModuleInfoClass *klass)
  428. {
  429.   GtkObjectClass *object_class;
  430.   GtkType type;
  431.  
  432.   object_class = GTK_OBJECT_CLASS (klass);
  433.  
  434.   type = object_class->type;
  435.  
  436.   object_class->destroy = module_info_destroy;
  437.  
  438.   module_info_signals[MODIFIED] =
  439.     gimp_signal_new ("modified", 0, type, 0, gimp_sigtype_void);
  440.  
  441.   gtk_object_class_add_signals (object_class, module_info_signals, LAST_SIGNAL);
  442. }
  443.  
  444. static void
  445. module_info_init (ModuleInfo *mod)
  446. {
  447.   /* don't need to do anything */
  448. }
  449.  
  450. static guint
  451. module_info_get_type (void)
  452. {
  453.   static guint module_info_type = 0;
  454.  
  455.   if (!module_info_type)
  456.     {
  457.       static const GtkTypeInfo module_info_info =
  458.       {
  459.     "ModuleInfo",
  460.     sizeof (ModuleInfo),
  461.     sizeof (ModuleInfoClass),
  462.     (GtkClassInitFunc) module_info_class_init,
  463.     (GtkObjectInitFunc) module_info_init,
  464.     /* reserved_1 */ NULL,
  465.         /* reserved_2 */ NULL,
  466.         (GtkClassInitFunc) NULL,
  467.       };
  468.  
  469.       module_info_type =
  470.     gtk_type_unique (gtk_object_get_type (), &module_info_info);
  471.     }
  472.  
  473.   return module_info_type;
  474. }
  475.  
  476. /* exported API: */
  477.  
  478. static void
  479. module_info_modified (ModuleInfo *mod)
  480. {
  481.   gtk_signal_emit (GTK_OBJECT (mod), module_info_signals[MODIFIED]);
  482. }
  483.  
  484. static ModuleInfo *
  485. module_info_new (void)
  486. {
  487.   return MODULE_INFO (gtk_type_new (module_info_get_type ()));
  488. }
  489.  
  490. static void
  491. module_info_free (ModuleInfo *mod)
  492. {
  493.   gtk_object_unref (GTK_OBJECT (mod));
  494. }
  495.  
  496.  
  497. /**************************************************************/
  498. /* helper functions */
  499.  
  500.  
  501. /* name must be of the form lib*.so (Unix) or *.dll (Win32) */
  502. static gboolean
  503. valid_module_name (const gchar *filename)
  504. {
  505.   const gchar *basename;
  506.   gint len;
  507.  
  508.   basename = g_basename (filename);
  509.  
  510.   len = strlen (basename);
  511.  
  512. #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) && !defined(__EMX__)
  513.   if (len < 3 + 1 + 3)
  514.     return FALSE;
  515.  
  516.   if (strncmp (basename, "lib", 3))
  517.     return FALSE;
  518.  
  519.   if (strcmp (basename + len - 3, ".so"))
  520.     return FALSE;
  521. #else
  522.   if (len < 1 + 4)
  523.       return FALSE;
  524.  
  525.   if (g_strcasecmp (basename + len - 4, ".dll"))
  526.     return FALSE;
  527. #endif
  528.  
  529.   return TRUE;
  530. }
  531.  
  532.  
  533. static gboolean
  534. module_inhibited (const gchar *fullpath, 
  535.           const gchar *inhibit_list)
  536. {
  537.   gchar *p;
  538.   gint   pathlen;
  539.   const gchar *start;
  540.   const gchar *end;
  541.  
  542.   /* common case optimisation: the list is empty */
  543.   if (!inhibit_list || *inhibit_list == '\000')
  544.     return FALSE;
  545.  
  546.   p = strstr (inhibit_list, fullpath);
  547.   if (!p)
  548.     return FALSE;
  549.  
  550.   /* we have a substring, but check for colons either side */
  551.   start = p;
  552.   while (start != inhibit_list && *start != G_SEARCHPATH_SEPARATOR)
  553.       start--;
  554.   if (*start == G_SEARCHPATH_SEPARATOR)
  555.       start++;
  556.  
  557.   end = strchr (p, G_SEARCHPATH_SEPARATOR);
  558.   if (!end)
  559.     end = inhibit_list + strlen (inhibit_list);
  560.  
  561.   pathlen = strlen (fullpath);
  562.   if ((end - start) == pathlen)
  563.     return TRUE;
  564.   else
  565.     return FALSE;
  566. }
  567.  
  568.  
  569. static void
  570. module_initialize (gchar *filename)
  571. {
  572.   ModuleInfo *mod;
  573.  
  574.   if (!valid_module_name (filename))
  575.     return;
  576.  
  577.   /* don't load if we already know about it */
  578.   if (module_find_by_path (filename))
  579.     return;
  580.  
  581.   mod = module_info_new ();
  582.  
  583.   mod->fullpath = g_strdup (filename);
  584.   mod->ondisk = TRUE;
  585.   mod->state = ST_MODULE_ERROR;
  586.  
  587.   mod->info = NULL;
  588.   mod->module = NULL;
  589.   mod->last_module_error = NULL;
  590.   mod->init = NULL;
  591.   mod->unload = NULL;
  592.  
  593.   /* Count of times main gimp is within the module.  Normally, this
  594.    * will be 1, and we assume that the module won't call its
  595.    * unload callback until it is satisfied that it's not in use any
  596.    * more.  refs can be 2 temporarily while we're running the module's
  597.    * unload function, to stop the module attempting to unload
  598.    * itself. */
  599.   mod->refs = 0;
  600.  
  601.   mod->load_inhibit = module_inhibited (mod->fullpath, module_db_load_inhibit);
  602.   if (!mod->load_inhibit)
  603.     {
  604.       if (be_verbose)
  605.     g_print (_("load module: \"%s\"\n"), filename);
  606.  
  607.       mod_load (mod, TRUE);
  608.     }
  609.   else
  610.     {
  611.       if (be_verbose)
  612.     g_print (_("skipping module: \"%s\"\n"), filename);
  613.  
  614.       mod->state = ST_UNLOADED_OK;
  615.     }
  616.  
  617.   gimp_set_add (modules, mod);
  618. }
  619.  
  620. static void
  621. mod_load (ModuleInfo *mod, 
  622.       gboolean    verbose)
  623. {
  624.   gpointer symbol;
  625.  
  626.   g_return_if_fail (mod->module == NULL);
  627.  
  628.   mod->module = g_module_open (mod->fullpath, G_MODULE_BIND_LAZY);
  629.   if (!mod->module)
  630.     {
  631.       mod->state = ST_MODULE_ERROR;
  632.  
  633.       if (mod->last_module_error)
  634.     g_free (mod->last_module_error);
  635.       mod->last_module_error = g_strdup (g_module_error ());
  636.  
  637.       if (verbose)
  638.     g_warning (_("module load error: %s: %s"),
  639.            mod->fullpath, mod->last_module_error);
  640.       return;
  641.     }
  642.  
  643. #ifdef __EMX__
  644.   if (g_module_symbol (mod->module, "gimp_main_funcs", &symbol))
  645.     {
  646.       *(struct main_funcs_struc **)symbol = gimp_main_funcs;
  647.     }
  648. #endif
  649.   /* find the module_init symbol */
  650.   if (!g_module_symbol (mod->module, "module_init", &symbol))
  651.     {
  652.       mod->state = ST_MODULE_ERROR;
  653.  
  654.       if (mod->last_module_error)
  655.     g_free (mod->last_module_error);
  656.       mod->last_module_error = g_strdup ("missing module_init() symbol");
  657.  
  658.       if (verbose)
  659.     g_warning ("%s: module_init() symbol not found", mod->fullpath);
  660.  
  661.       g_module_close (mod->module);
  662.       mod->module = NULL;
  663.       mod->info = NULL;
  664.       return;
  665.     }
  666.  
  667.   /* run module's initialisation */
  668.   mod->init = symbol;
  669.   mod->info = NULL;
  670.   gimp_module_ref (mod); /* loaded modules are assumed to have a ref of 1 */
  671.   if (mod->init (&mod->info) == GIMP_MODULE_UNLOAD)
  672.     {
  673.       mod->state = ST_LOAD_FAILED;
  674.       gimp_module_unref (mod);
  675.       mod->info = NULL;
  676.       return;
  677.     }
  678.  
  679.   /* module is now happy */
  680.   mod->state = ST_LOADED_OK;
  681.   TRC (("loaded module %s, state at %p\n", mod->fullpath, mod));
  682.  
  683.   /* do we have an unload function? */
  684.   if (g_module_symbol (mod->module, "module_unload", &symbol))
  685.     mod->unload = symbol;
  686.   else
  687.     mod->unload = NULL;
  688. }
  689.  
  690.  
  691. static void
  692. mod_unload_completed_callback (void *data)
  693. {
  694.   ModuleInfo *mod = data;
  695.  
  696.   g_return_if_fail (mod->state == ST_UNLOAD_REQUESTED);
  697.  
  698.   /* lose the ref we gave this module when we loaded it,
  699.    * since the module's now happy to be unloaded. */
  700.   gimp_module_unref (mod);
  701.   mod->info = NULL;
  702.  
  703.   mod->state = ST_UNLOADED_OK;
  704.  
  705.   TRC (("module unload completed callback for %p\n", mod));
  706.  
  707.   module_info_modified (mod);
  708. }
  709.  
  710. static void
  711. mod_unload (ModuleInfo *mod, 
  712.         gboolean    verbose)
  713. {
  714.   g_return_if_fail (mod->module != NULL);
  715.   g_return_if_fail (mod->unload != NULL);
  716.  
  717.   if (mod->state == ST_UNLOAD_REQUESTED)
  718.     return;
  719.  
  720.   mod->state = ST_UNLOAD_REQUESTED;
  721.  
  722.   TRC (("module unload requested for %p\n", mod));
  723.  
  724.   /* Send the unload request.  Need to ref the module so we don't
  725.    * accidentally unload it while this call is in progress (eg if the
  726.    * callback is called before the unload function returns). */
  727.   gimp_module_ref (mod);
  728.   mod->unload (mod->info->shutdown_data, mod_unload_completed_callback, mod);
  729.  
  730.   gtk_idle_add ((GtkFunction) mod_idle_unref, (gpointer) mod);
  731. }
  732.  
  733. static gboolean
  734. mod_idle_unref (ModuleInfo *mod)
  735. {
  736.   gimp_module_unref (mod);
  737.  
  738.   return FALSE;
  739. }
  740.  
  741. #ifdef DUMP_DB
  742. static void
  743. print_module_info (gpointer data, 
  744.            gpointer user_data)
  745. {
  746.   ModuleInfo *i = data;
  747.  
  748.   g_print ("\n%s: %s\n",
  749.        i->fullpath, statename[i->state]);
  750.   g_print ("  module:%p  lasterr:%s  init:%p  unload:%p\n",
  751.        i->module, i->last_module_error? i->last_module_error : "NONE",
  752.        i->init, i->unload);
  753.   if (i->info)
  754.     {
  755.       g_print ("  shutdown_data: %p\n"
  756.            "  purpose:   %s\n"
  757.            "  author:    %s\n"
  758.            "  version:   %s\n"
  759.            "  copyright: %s\n"
  760.            "  date:      %s\n",
  761.            i->info->shutdown_data,
  762.            i->info->purpose, i->info->author, i->info->version,
  763.            i->info->copyright, i->info->date);
  764.     }
  765. }
  766. #endif
  767.  
  768.  
  769.  
  770. /**************************************************************/
  771. /* UI functions */
  772.  
  773. static void
  774. browser_popdown_callback (GtkWidget *widget,
  775.               gpointer   data)
  776. {
  777.   gtk_widget_destroy (GTK_WIDGET (data));
  778. }
  779.  
  780. static void
  781. browser_destroy_callback (GtkWidget *widget,
  782.               gpointer   data)
  783. {
  784.   gtk_signal_disconnect_by_data (GTK_OBJECT (modules), data);
  785.   gimp_set_remove_handler (modules, modules_handler);
  786.   g_free (data);
  787. }
  788.  
  789. static void
  790. browser_load_inhibit_callback (GtkWidget *widget,
  791.                    gpointer   data)
  792. {
  793.   BrowserState *st = data;
  794.   gboolean new_value;
  795.  
  796.   g_return_if_fail (st->last_update != NULL);
  797.  
  798.   new_value = ! GTK_TOGGLE_BUTTON (widget)->active;
  799.  
  800.   if (new_value == st->last_update->load_inhibit)
  801.     return;
  802.  
  803.   st->last_update->load_inhibit = new_value;
  804.   module_info_modified (st->last_update);
  805.  
  806.   need_to_rewrite_modulerc = TRUE;
  807. }
  808.  
  809. static void
  810. browser_info_update (ModuleInfo   *mod, 
  811.              BrowserState *st)
  812. {
  813.   gint i;
  814.   const gchar *text[NUM_INFO_LINES - 1];
  815.   gchar *status;
  816.  
  817.   /* only update the info if we're actually showing it */
  818.   if (mod != st->last_update)
  819.     return;
  820.  
  821.   if (!mod)
  822.     {
  823.       for (i=0; i < NUM_INFO_LINES; i++)
  824.     gtk_label_set_text (GTK_LABEL (st->label[i]), "");
  825.       gtk_label_set_text (GTK_LABEL(st->button_label), _("<No modules>"));
  826.       gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE);
  827.       gtk_widget_set_sensitive (GTK_WIDGET (st->load_inhibit_check), FALSE);
  828.       return;
  829.     }
  830.  
  831.   if (mod->info)
  832.     {
  833.       text[0] = mod->info->purpose;
  834.       text[1] = mod->info->author;
  835.       text[2] = mod->info->version;
  836.       text[3] = mod->info->copyright;
  837.       text[4] = mod->info->date;
  838.       text[5] = mod->ondisk? _("on disk") : _("only in memory");
  839.     }
  840.   else
  841.     {
  842.       text[0] = "--";
  843.       text[1] = "--";
  844.       text[2] = "--";
  845.       text[3] = "--";
  846.       text[4] = "--";
  847.       text[5] = mod->ondisk? _("on disk") : _("nowhere (click 'refresh')");
  848.     }
  849.  
  850.   if (mod->state == ST_MODULE_ERROR && mod->last_module_error)
  851.     status = g_strdup_printf ("%s (%s)", gettext (statename[mod->state]),
  852.                   mod->last_module_error);
  853.   else
  854.     {
  855.       status = g_strdup (gettext (statename[mod->state]));
  856.     }
  857.  
  858.   for (i=0; i < NUM_INFO_LINES - 1; i++)
  859.     {
  860.       gtk_label_set_text (GTK_LABEL (st->label[i]), gettext (text[i]));
  861.     }
  862.  
  863.   gtk_label_set_text (GTK_LABEL (st->label[NUM_INFO_LINES-1]), status);
  864.  
  865.   g_free (status);
  866.  
  867.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (st->load_inhibit_check),
  868.                 !mod->load_inhibit);
  869.   gtk_widget_set_sensitive (GTK_WIDGET (st->load_inhibit_check), TRUE);
  870.  
  871.   /* work out what the button should do (if anything) */
  872.   switch (mod->state)
  873.     {
  874.     case ST_MODULE_ERROR:
  875.     case ST_LOAD_FAILED:
  876.     case ST_UNLOADED_OK:
  877.       gtk_label_set_text (GTK_LABEL(st->button_label), _("Load"));
  878.       gtk_widget_set_sensitive (GTK_WIDGET (st->button), mod->ondisk);
  879.       break;
  880.  
  881.     case ST_UNLOAD_REQUESTED:
  882.       gtk_widget_set_sensitive (GTK_WIDGET (st->button), FALSE);
  883.       break;
  884.  
  885.     case ST_LOADED_OK:
  886.       gtk_label_set_text (GTK_LABEL(st->button_label), _("Unload"));
  887.       gtk_widget_set_sensitive (GTK_WIDGET (st->button),
  888.                 mod->unload? TRUE : FALSE);
  889.       break;    
  890.     }
  891. }
  892.  
  893. static void
  894. browser_info_init (BrowserState *st, 
  895.            GtkWidget    *table)
  896. {
  897.   GtkWidget *label;
  898.   gint i;
  899.  
  900.   gchar *text[] =
  901.   {
  902.     N_("Purpose:"),
  903.     N_("Author:"),
  904.     N_("Version:"),
  905.     N_("Copyright:"),
  906.     N_("Date:"),
  907.     N_("Location:"),
  908.     N_("State:")
  909.   };
  910.  
  911.   for (i=0; i < sizeof(text) / sizeof(char *); i++)
  912.     {
  913.       label = gtk_label_new (gettext (text[i]));
  914.       gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  915.       gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1,
  916.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2);
  917.       gtk_widget_show (label);
  918.  
  919.       st->label[i] = gtk_label_new ("");
  920.       gtk_misc_set_alignment (GTK_MISC (st->label[i]), 0.0, 0.5);
  921.       gtk_table_attach (GTK_TABLE (st->table), st->label[i], 1, 2, i, i+1,
  922.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2);
  923.       gtk_widget_show (st->label[i]);
  924.     }
  925.  
  926.   st->load_inhibit_check =
  927.     gtk_check_button_new_with_label (_("Autoload during startup"));
  928.   gtk_widget_show (st->load_inhibit_check);
  929.   gtk_table_attach (GTK_TABLE (table), st->load_inhibit_check,
  930.             0, 2, i, i+1,
  931.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 2);
  932.   gtk_signal_connect (GTK_OBJECT (st->load_inhibit_check), "toggled",
  933.               browser_load_inhibit_callback, st);
  934. }
  935.  
  936. static void
  937. browser_select_callback (GtkWidget *widget, 
  938.              GtkWidget *child)
  939. {
  940.   ModuleInfo *i;
  941.   BrowserState *st;
  942.  
  943.   i = gtk_object_get_user_data (GTK_OBJECT (child));
  944.   st = gtk_object_get_user_data (GTK_OBJECT (widget));
  945.  
  946.   if (st->last_update == i)
  947.     return;
  948.  
  949.   st->last_update = i;
  950.  
  951.   browser_info_update (st->last_update, st);
  952. }
  953.  
  954.  
  955. static void
  956. browser_load_unload_callback (GtkWidget *widget, 
  957.                   gpointer   data)
  958. {
  959.   BrowserState *st = data;
  960.  
  961.   if (st->last_update->state == ST_LOADED_OK)
  962.     mod_unload (st->last_update, FALSE);
  963.   else
  964.     mod_load (st->last_update, FALSE);
  965.  
  966.   module_info_modified (st->last_update);
  967. }
  968.  
  969.  
  970. static void
  971. make_list_item (gpointer data, 
  972.         gpointer user_data)
  973. {
  974.   ModuleInfo   *info = data;
  975.   BrowserState *st = user_data;
  976.   GtkWidget    *list_item;
  977.  
  978.   if (!st->last_update)
  979.     st->last_update = info;
  980.  
  981.   list_item = gtk_list_item_new_with_label (info->fullpath);
  982.  
  983.   gtk_widget_show (list_item);
  984.   gtk_object_set_user_data (GTK_OBJECT (list_item), info);
  985.  
  986.   gtk_container_add (GTK_CONTAINER (st->list), list_item);
  987. }
  988.  
  989.  
  990. static void
  991. browser_info_add (GimpSet      *set, 
  992.           ModuleInfo   *mod, 
  993.           BrowserState *st)
  994. {
  995.   make_list_item (mod, st);
  996. }
  997.  
  998.  
  999. static void
  1000. browser_info_remove (GimpSet      *set, 
  1001.              ModuleInfo   *mod, 
  1002.              BrowserState *st)
  1003. {
  1004.   GList *dlist, *free_list;
  1005.   GtkWidget *list_item;
  1006.   ModuleInfo *i;
  1007.  
  1008.   dlist = gtk_container_children (GTK_CONTAINER (st->list));
  1009.   free_list = dlist;
  1010.  
  1011.   while (dlist)
  1012.   {
  1013.     list_item = dlist->data;
  1014.  
  1015.     i = gtk_object_get_user_data (GTK_OBJECT (list_item));
  1016.     g_return_if_fail (i != NULL);
  1017.  
  1018.     if (i == mod)
  1019.     {
  1020.       gtk_container_remove (GTK_CONTAINER (st->list), list_item);
  1021.       g_list_free(free_list);
  1022.       return;
  1023.     }
  1024.  
  1025.     dlist = dlist->next;
  1026.   }
  1027.  
  1028.   g_warning ("tried to remove module that wasn't in brower's list");
  1029.   g_list_free(free_list);
  1030. }
  1031.  
  1032.  
  1033.  
  1034. static void
  1035. module_db_module_ondisk (gpointer data, 
  1036.              gpointer user_data)
  1037. {
  1038.   ModuleInfo *mod = data;
  1039.   struct stat statbuf;
  1040.   gint ret;
  1041.   gint old_ondisk = mod->ondisk;
  1042.   GSList **kill_list = user_data;
  1043.  
  1044.   ret = stat (mod->fullpath, &statbuf);
  1045.   if (ret != 0)
  1046.     mod->ondisk = FALSE;
  1047.   else
  1048.     mod->ondisk = TRUE;
  1049.  
  1050.   /* if it's not on the disk, and it isn't in memory, mark it to be
  1051.    * removed later. */
  1052.   if (!mod->ondisk && !mod->module)
  1053.     {
  1054.       *kill_list = g_slist_append (*kill_list, mod);
  1055.       mod = NULL;
  1056.     }
  1057.  
  1058.   if (mod && mod->ondisk != old_ondisk)
  1059.     module_info_modified (mod);
  1060. }
  1061.  
  1062.  
  1063. static void
  1064. module_db_module_remove (gpointer data, 
  1065.              gpointer user_data)
  1066. {
  1067.   ModuleInfo *mod = data;
  1068.  
  1069.   gimp_set_remove (modules, mod);
  1070.  
  1071.   module_info_free (mod);
  1072. }
  1073.  
  1074.  
  1075.  
  1076. typedef struct
  1077. {
  1078.   const gchar *search_key;
  1079.   ModuleInfo  *found;
  1080. } find_by_path_closure;
  1081.  
  1082. static void
  1083. module_db_path_cmp (gpointer data, 
  1084.             gpointer user_data)
  1085. {
  1086.   ModuleInfo *mod = data;
  1087.   find_by_path_closure *cl = user_data;
  1088.  
  1089.   if (!strcmp (mod->fullpath, cl->search_key))
  1090.     cl->found = mod;
  1091. }
  1092.  
  1093. static ModuleInfo *
  1094. module_find_by_path (const char *fullpath)
  1095. {
  1096.   find_by_path_closure cl;
  1097.  
  1098.   cl.found = NULL;
  1099.   cl.search_key = fullpath;
  1100.  
  1101.   gimp_set_foreach (modules, module_db_path_cmp, &cl);
  1102.  
  1103.   return cl.found;
  1104. }
  1105.  
  1106.  
  1107.  
  1108. static void
  1109. browser_refresh_callback (GtkWidget *widget, 
  1110.               gpointer   data)
  1111. {
  1112.   GSList *kill_list = NULL;
  1113.  
  1114.   /* remove modules we don't have on disk anymore */
  1115.   gimp_set_foreach (modules, module_db_module_ondisk, &kill_list);
  1116.   g_slist_foreach (kill_list, module_db_module_remove, NULL);
  1117.   g_slist_free (kill_list);
  1118.   kill_list = NULL;
  1119.  
  1120.   /* walk filesystem and add new things we find */
  1121.   datafiles_read_directories (module_path,
  1122.                   module_initialize, 0 /* no flags */);
  1123. }
  1124.  
  1125.  
  1126. static void
  1127. gimp_module_ref (ModuleInfo *mod)
  1128. {
  1129.   g_return_if_fail (mod->refs >= 0);
  1130.   g_return_if_fail (mod->module != NULL);
  1131.   mod->refs++;
  1132. }
  1133.  
  1134. static void
  1135. gimp_module_unref (ModuleInfo *mod)
  1136. {
  1137.   g_return_if_fail (mod->refs > 0);
  1138.   g_return_if_fail (mod->module != NULL);
  1139.  
  1140.   mod->refs--;
  1141.  
  1142.   if (mod->refs == 0)
  1143.     {
  1144.       TRC (("module %p refs hit 0, g_module_closing it\n", mod));
  1145.       g_module_close (mod->module);
  1146.       mod->module = NULL;
  1147.     }
  1148. }
  1149.  
  1150. /* End of module_db.c */
  1151.