Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.253
diff -u -p -r1.253 Makefile.am
--- gtk/Makefile.am	25 Aug 2004 16:21:05 -0000	1.253
+++ gtk/Makefile.am	31 Aug 2004 04:24:23 -0000
@@ -203,6 +203,7 @@ gtk_public_h_sources =          \
 	gtkmenushell.h		\
 	gtkmessagedialog.h	\
 	gtkmisc.h		\
+	gtkmodules.h		\
 	gtknotebook.h		\
 	gtkobject.h		\
 	gtkoldeditable.h	\
@@ -422,6 +423,7 @@ gtk_c_sources =                 \
 	gtkmenushell.c		\
 	gtkmessagedialog.c	\
 	gtkmisc.c		\
+	gtkmodules.c		\
 	gtknotebook.c		\
 	gtkobject.c		\
 	gtkoldeditable.c	\
Index: gtk/gtk.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtk.h,v
retrieving revision 1.72
diff -u -p -r1.72 gtk.h
--- gtk/gtk.h	17 Aug 2004 16:06:39 -0000	1.72
+++ gtk/gtk.h	31 Aug 2004 04:24:23 -0000
@@ -118,6 +118,7 @@
 #include <gtk/gtkmenushell.h>
 #include <gtk/gtkmessagedialog.h>
 #include <gtk/gtkmisc.h>
+#include <gtk/gtkmodules.h>
 #include <gtk/gtknotebook.h>
 #include <gtk/gtkobject.h>
 #include <gtk/gtkoldeditable.h>
Index: gtk/gtkdebug.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkdebug.h,v
retrieving revision 1.20
diff -u -p -r1.20 gtkdebug.h
--- gtk/gtkdebug.h	20 Jun 2002 19:29:16 -0000	1.20
+++ gtk/gtkdebug.h	31 Aug 2004 04:24:23 -0000
@@ -38,7 +38,8 @@ typedef enum {
   GTK_DEBUG_TREE        = 1 << 3,
   GTK_DEBUG_UPDATES     = 1 << 4,
   GTK_DEBUG_KEYBINDINGS = 1 << 5,
-  GTK_DEBUG_MULTIHEAD   = 1 << 6
+  GTK_DEBUG_MULTIHEAD   = 1 << 6,
+  GTK_DEBUG_MODULES     = 1 << 7
 } GtkDebugFlag;
 
 #ifdef G_ENABLE_DEBUG
Index: gtk/gtkmain.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmain.c,v
retrieving revision 1.240
diff -u -p -r1.240 gtkmain.c
--- gtk/gtkmain.c	9 Aug 2004 16:59:52 -0000	1.240
+++ gtk/gtkmain.c	31 Aug 2004 04:24:23 -0000
@@ -34,10 +34,11 @@
 #include <libintl.h>
 #endif
 
+#include <glib.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <gmodule.h>
 #ifdef G_OS_UNIX
 #include <unistd.h>
 #include <sys/types.h>		/* For uid_t, gid_t */
@@ -48,7 +49,7 @@
 #undef STRICT
 #endif
 
-#include <pango/pango-utils.h>	/* For pango_split_file_list */
+#include <pango/pango-types.h>	/* For pango_language_from_string */
 
 #include "gtkalias.h"
 #include "gtkintl.h"
@@ -59,6 +60,7 @@
 #include "gtkdnd.h"
 #include "gtkversion.h"
 #include "gtkmain.h"
+#include "gtkmodules.h"
 #include "gtkrc.h"
 #include "gtkselection.h"
 #include "gtksettings.h"
@@ -73,7 +75,6 @@ typedef struct _GtkInitFunction		 GtkIni
 typedef struct _GtkQuitFunction		 GtkQuitFunction;
 typedef struct _GtkClosure	         GtkClosure;
 typedef struct _GtkKeySnooperData	 GtkKeySnooperData;
-typedef struct _GtkModuleInfo            GtkModuleInfo;
 
 struct _GtkInitFunction
 {
@@ -105,12 +106,6 @@ struct _GtkKeySnooperData
   guint id;
 };
 
-struct _GtkModuleInfo
-{
-  GtkModuleInitFunc init_func;
-  GtkModuleDisplayInitFunc display_init_func;
-};
-
 static gint  gtk_quit_invoke_function	 (GtkQuitFunction    *quitf);
 static void  gtk_quit_destroy		 (GtkQuitFunction    *quitf);
 static gint  gtk_invoke_key_snoopers	 (GtkWidget	     *grab_widget,
@@ -137,13 +132,6 @@ const guint gtk_micro_version = GTK_MICR
 const guint gtk_binary_age = GTK_BINARY_AGE;
 const guint gtk_interface_age = GTK_INTERFACE_AGE;
 
-static GSList *gtk_modules;
-
-/* Saved argc,argv for delayed module initialization
- */
-static gint    gtk_argc = 0;
-static gchar **gtk_argv = NULL;
-
 static guint gtk_main_loop_level = 0;
 static gint gtk_initialized = FALSE;
 static GList *current_events = NULL;
@@ -168,7 +156,8 @@ static const GDebugKey gtk_debug_keys[] 
   {"tree", GTK_DEBUG_TREE},
   {"updates", GTK_DEBUG_UPDATES},
   {"keybindings", GTK_DEBUG_KEYBINDINGS},
-  {"multihead", GTK_DEBUG_MULTIHEAD}
+  {"multihead", GTK_DEBUG_MULTIHEAD},
+  {"modules", GTK_DEBUG_MODULES}
 };
 
 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
@@ -334,260 +323,6 @@ _gtk_get_data_prefix (void)
 
 #endif /* G_OS_WIN32 */
 
-static gchar **
-get_module_path (void)
-{
-  const gchar *module_path_env;
-  const gchar *exe_prefix;
-  const gchar *home_dir;
-  gchar *home_gtk_dir = NULL;
-  gchar *module_path;
-  gchar *default_dir;
-  static gchar **result = NULL;
-
-  if (result)
-    return result;
-
-  home_dir = g_get_home_dir();
-  if (home_dir)
-    home_gtk_dir = g_build_filename (home_dir, ".gtk-2.0", NULL);
-
-  module_path_env = g_getenv ("GTK_PATH");
-  exe_prefix = g_getenv ("GTK_EXE_PREFIX");
-
-  if (exe_prefix)
-    default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", NULL);
-  else
-    default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", NULL);
-
-  if (module_path_env && home_gtk_dir)
-    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
-				module_path_env, home_gtk_dir, default_dir, NULL);
-  else if (module_path_env)
-    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
-				module_path_env, default_dir, NULL);
-  else if (home_gtk_dir)
-    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
-				home_gtk_dir, default_dir, NULL);
-  else
-    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
-				default_dir, NULL);
-
-  g_free (home_gtk_dir);
-  g_free (default_dir);
-
-  result = pango_split_file_list (module_path);
-  g_free (module_path);
-
-  return result;
-}
-
-/**
- * _gtk_get_module_path:
- * @type: the type of the module, for instance 'modules', 'engines', immodules'
- * 
- * Determines the search path for a particular type of module.
- * 
- * Return value: the search path for the module type. Free with g_strfreev().
- **/
-gchar **
-_gtk_get_module_path (const gchar *type)
-{
-  gchar **paths = get_module_path();
-  gchar **path;
-  gchar **result;
-  gint count = 0;
-
-  for (path = paths; *path; path++)
-    count++;
-
-  result = g_new (gchar *, count * 4 + 1);
-
-  count = 0;
-  for (path = get_module_path (); *path; path++)
-    {
-      gint use_version, use_host;
-      
-      for (use_version = TRUE; use_version >= FALSE; use_version--)
-	for (use_host = TRUE; use_host >= FALSE; use_host--)
-	  {
-	    gchar *tmp_dir;
-	    
-	    if (use_version && use_host)
-	      tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, GTK_HOST, type, NULL);
-	    else if (use_version)
-	      tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, type, NULL);
-	    else if (use_host)
-	      tmp_dir = g_build_filename (*path, GTK_HOST, type, NULL);
-	    else
-	      tmp_dir = g_build_filename (*path, type, NULL);
-
-	    result[count++] = tmp_dir;
-	  }
-    }
-
-  result[count++] = NULL;
-
-  return result;
-}
-
-/* Like g_module_path, but use .la as the suffix
- */
-static gchar*
-module_build_la_path (const gchar *directory,
-		      const gchar *module_name)
-{
-	gchar *filename;
-	gchar *result;
-	
-	if (strncmp (module_name, "lib", 3) == 0)
-		filename = (gchar *)module_name;
-	else
-		filename =  g_strconcat ("lib", module_name, ".la", NULL);
-
-	if (directory && *directory)
-		result = g_build_filename (directory, filename, NULL);
-	else
-		result = g_strdup (filename);
-
-	if (filename != module_name)
-		g_free (filename);
-
-	return result;
-}
-
-/**
- * _gtk_find_module:
- * @name: the name of the module
- * @type: the type of the module, for instance 'modules', 'engines', immodules'
- * 
- * Looks for a dynamically loadable module named @name of type @type in the
- * standard GTK+ module search path.
- * 
- * Return value: the pathname to the found module, or %NULL if it wasn't found.
- *  Free with g_free().
- **/
-gchar *
-_gtk_find_module (const gchar *name,
-		  const gchar *type)
-{
-  gchar **paths;
-  gchar **path;
-  gchar *module_name = NULL;
-
-  if (g_path_is_absolute (name))
-    return g_strdup (name);
-
-  paths = _gtk_get_module_path (type);
-  for (path = paths; *path; path++)
-    {
-      gchar *tmp_name;
-
-      tmp_name = g_module_build_path (*path, name);
-      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
-	{
-	  module_name = tmp_name;
-	  goto found;
-	}
-      g_free(tmp_name);
-
-      tmp_name = module_build_la_path (*path, name);
-      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
-	{
-	  module_name = tmp_name;
-	  goto found;
-	}
-      g_free(tmp_name);
-    }
-
- found:
-  g_strfreev (paths);
-  return module_name;
-}
-
-static GModule *
-find_module (const gchar *name)
-{
-  GModule *module;
-  gchar *module_name;
-
-  module_name = _gtk_find_module (name, "modules");
-  if (!module_name)
-    {
-      /* As last resort, try loading without an absolute path (using system
-       * library path)
-       */
-      module_name = g_module_build_path (NULL, name);
-    }
-  
-  module = g_module_open (module_name, G_MODULE_BIND_LAZY);
-  g_free(module_name);
-
-  return module;
-}
-
-static GSList *
-load_module (GSList      *module_list,
-	     const gchar *name)
-{
-  GtkModuleInitFunc modinit_func = NULL;
-  GtkModuleInfo *info;
-  GModule *module = NULL;
-  
-  if (g_module_supported ())
-    {
-      module = find_module (name);
-      if (module &&
-	  g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
-	  modinit_func)
-	{
-	  if (!g_slist_find (module_list, (gconstpointer) modinit_func))
-	    {
-	      g_module_make_resident (module);
-	      info = g_new (GtkModuleInfo, 1);
-
-	      info->init_func = modinit_func;
-	      g_module_symbol (module, "gtk_module_display_init",
-			       (gpointer *) &info->display_init_func);
-	      
-	      module_list = g_slist_prepend (module_list, info);
-	    }
-	  else
-	    {
-	      g_module_close (module);
-	      module = NULL;
-	    }
-	}
-    }
-  if (!modinit_func)
-    {
-      g_message ("Failed to load module \"%s\": %s",
-		 module ? g_module_name (module) : name,
-		 g_module_error ());
-      if (module)
-	g_module_close (module);
-    }
-  
-  return module_list;
-}
-
-static GSList *
-load_modules (const char *module_str)
-{
-  gchar **module_names = pango_split_file_list (module_str);
-  GSList *module_list = NULL;
-  gint i;
-  
-  for (i = 0; module_names[i]; i++)
-    module_list = load_module (module_list, module_names[i]);
-  
-  module_list = g_slist_reverse (module_list);
-  
-  g_strfreev (module_names);
-
-  return module_list;
-}
-
 static gboolean do_setlocale = TRUE;
 
 /**
@@ -614,51 +349,6 @@ gtk_disable_setlocale (void)
 #undef gtk_init_check
 #endif
 
-static void
-default_display_notify_cb (GdkDisplayManager *display_manager)
-{
-  GSList *slist;
-
-  /* Initialize non-multihead-aware modules when the
-   * default display is first set to a non-NULL value.
-   */
-  static gboolean initialized = FALSE;
-
-  if (!gdk_display_get_default () || initialized)
-    return;
-
-  initialized = TRUE;
-
-  for (slist = gtk_modules; slist; slist = slist->next)
-    {
-      if (slist->data)
-	{
-	  GtkModuleInfo *info = slist->data;
-
-	  if (!info->display_init_func)
-	    info->init_func (&gtk_argc, &gtk_argv);
-	}
-    }
-}
-
-static void
-display_opened_cb (GdkDisplayManager *display_manager,
-		   GdkDisplay        *display)
-{
-  GSList *slist;
-  
-  for (slist = gtk_modules; slist; slist = slist->next)
-    {
-      if (slist->data)
-	{
-	  GtkModuleInfo *info = slist->data;
-
-	  if (info->display_init_func)
-	    info->display_init_func (display);
-	}
-    }
-}
-
 /**
  * gtk_parse_args:
  * @argc: a pointer to the number of command line arguments.
@@ -680,9 +370,7 @@ gboolean
 gtk_parse_args (int    *argc,
 		char ***argv)
 {
-  GString *gtk_modules_string = NULL;
-  GSList *slist;
-  GdkDisplayManager *display_manager;
+  GString *gtk_modules_string;
   const gchar *env_string;
 
   if (gtk_initialized)
@@ -718,9 +406,11 @@ gtk_parse_args (int    *argc,
     }
 #endif	/* G_ENABLE_DEBUG */
 
+  gtk_modules_string = g_string_new (NULL);
+
   env_string = g_getenv ("GTK_MODULES");
   if (env_string)
-    gtk_modules_string = g_string_new (env_string);
+    g_string_append (gtk_modules_string, env_string);
 
   if (argc && argv)
     {
@@ -745,11 +435,7 @@ gtk_parse_args (int    *argc,
 
 	      if (module_name && *module_name)
 		{
-		  if (gtk_modules_string)
-		    g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
-		  else
-		    gtk_modules_string = g_string_new (NULL);
-
+		  g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
 		  g_string_append (gtk_modules_string, module_name);
 		}
 	    }
@@ -823,23 +509,11 @@ gtk_parse_args (int    *argc,
 	      *argc -= k;
 	    }
 	}
-
-      gtk_argv = g_malloc ((gtk_argc + 1) * sizeof (char*));
-      for (i = 0; i < gtk_argc; i++)
-	gtk_argv[i] = g_strdup ((*argv)[i]);
-      gtk_argv[gtk_argc] = NULL;
     }
 
   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
     gdk_window_set_debug_updates (TRUE);
 
-  /* load gtk modules */
-  if (gtk_modules_string)
-    {
-      gtk_modules = load_modules (gtk_modules_string->str);
-      g_string_free (gtk_modules_string, TRUE);
-    }
-
 #ifdef ENABLE_NLS
   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
   bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR);
@@ -866,30 +540,14 @@ gtk_parse_args (int    *argc,
   gtk_type_init (0);
   _gtk_accel_map_init ();  
   _gtk_rc_init ();
-  
+
   /* Set the 'initialized' flag.
    */
   gtk_initialized = TRUE;
 
-  display_manager = gdk_display_manager_get ();
-  g_signal_connect (display_manager, "notify::default-display",
-		    G_CALLBACK (default_display_notify_cb), NULL);
-  g_signal_connect (display_manager, "display-opened",
-		    G_CALLBACK (display_opened_cb), NULL);
-
-  /* initialize multhead aware gtk modules; for other modules,
-   * we wait until we have a display open;
-   */
-  for (slist = gtk_modules; slist; slist = slist->next)
-    {
-      if (slist->data)
-	{
-	  GtkModuleInfo *info = slist->data;
-
-	  if (info->display_init_func)
-	    info->init_func (argc, argv);
-	}
-    }
+  /* load gtk modules */
+  _gtk_modules_init (*argc, *argv, gtk_modules_string->str);
+  g_string_free (gtk_modules_string, TRUE);
   
   return TRUE;
 }
Index: gtk/gtkmain.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmain.h,v
retrieving revision 1.54
diff -u -p -r1.54 gtkmain.h
--- gtk/gtkmain.h	13 Jul 2004 14:49:02 -0000	1.54
+++ gtk/gtkmain.h	31 Aug 2004 04:24:23 -0000
@@ -57,9 +57,6 @@ extern "C" {
 
 #endif /* GTK_DISABLE_DEPRECATED */
 
-typedef void	(*GtkModuleInitFunc)        (gint	  *argc,
-				             gchar      ***argv);
-typedef void	(*GtkModuleDisplayInitFunc) (GdkDisplay   *display);
 typedef gint	(*GtkKeySnoopFunc)	    (GtkWidget	  *grab_widget,
 					     GdkEventKey  *event,
 					     gpointer	   func_data);
@@ -213,10 +210,6 @@ gboolean _gtk_boolean_handled_accumulato
                                    GValue                *return_accu,
                                    const GValue          *handler_return,
                                    gpointer               dummy);
-
-gchar * _gtk_find_module     (const gchar *name,
-			      const gchar *type);
-gchar **_gtk_get_module_path (const gchar *type);
 
 gchar *_gtk_get_lc_ctype (void);
 
Index: gtk/gtksettings.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtksettings.c,v
retrieving revision 1.54
diff -u -p -r1.54 gtksettings.c
--- gtk/gtksettings.c	9 Aug 2004 16:59:52 -0000	1.54
+++ gtk/gtksettings.c	31 Aug 2004 04:24:24 -0000
@@ -63,6 +63,7 @@ enum {
   PROP_DND_DRAG_THRESHOLD,
   PROP_FONT_NAME,
   PROP_ICON_SIZES,
+  PROP_MODULES,
   PROP_XFT_ANTIALIAS,
   PROP_XFT_HINTING,
   PROP_XFT_HINTSTYLE,
@@ -89,6 +90,8 @@ static guint	settings_install_property_p
 						  GParamSpec            *pspec,
 						  GtkRcPropertyParser    parser);
 static void    settings_update_double_click      (GtkSettings           *settings);
+static void    settings_update_modules           (GtkSettings           *settings);
+
 
 
 /* --- variables --- */
@@ -360,6 +363,15 @@ gtk_settings_class_init (GtkSettingsClas
                                              NULL);
   g_assert (result == PROP_ICON_SIZES);
 
+  result = settings_install_property_parser (class,
+                                             g_param_spec_string ("gtk-modules",
+								  P_("GTK Modules"),
+								  P_("List of currently active GTK modules"),
+								  NULL,
+								  G_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_MODULES);
+
 #ifdef GDK_WINDOWING_X11
   result = settings_install_property_parser (class,
 					     g_param_spec_int ("gtk-xft-antialias",
@@ -584,6 +596,9 @@ gtk_settings_notify (GObject    *object,
 
   switch (property_id)
     {
+    case PROP_MODULES:
+      settings_update_modules (settings);
+      break;
     case PROP_DOUBLE_CLICK_TIME:
     case PROP_DOUBLE_CLICK_DISTANCE:
       settings_update_double_click (settings);
@@ -1362,4 +1377,19 @@ settings_update_double_click (GtkSetting
       gdk_display_set_double_click_time (display, double_click_time);
       gdk_display_set_double_click_distance (display, double_click_distance);
     }
+}
+
+static void
+settings_update_modules (GtkSettings *settings)
+{
+  GdkDisplay *display = gdk_screen_get_display (settings->screen);
+  gchar *modules;
+  
+  g_object_get (settings, 
+		"gtk-modules", &modules,
+		NULL);
+  
+  _gtk_modules_settings_changed (settings, modules);
+  
+  g_free (modules);
 }
Index: gdk/x11/gdkevents-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkevents-x11.c,v
retrieving revision 1.139
diff -u -p -r1.139 gdkevents-x11.c
--- gdk/x11/gdkevents-x11.c	9 Aug 2004 20:14:43 -0000	1.139
+++ gdk/x11/gdkevents-x11.c	31 Aug 2004 04:24:24 -0000
@@ -2710,6 +2710,7 @@ static struct
   { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
   { "Gtk/IMPreeditStyle", "gtk-im-preedit-style" },
   { "Gtk/IMStatusStyle", "gtk-im-status-style" },
+  { "Gtk/Modules", "gtk-modules" },
   { "Gtk/FileChooserBackend", "gtk-file-chooser-backend" },
   { "Gtk/ButtonImages", "gtk-button-images" },
   { "Gtk/MenuImages", "gtk-menu-images" },
--- /dev/null	2004-07-29 15:44:00.000000000 -0400
+++ gtk/gtkmodules.h	2004-08-30 20:24:00.000000000 -0400
@@ -0,0 +1,50 @@
+/* GTK - The GIMP Toolkit
+ * Copyright 1998-2002 Tim Janik, Red Hat, Inc., and others.
+ * Copyright (C) 2003 Alex Graveley
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_MODULES_H__
+#define __GTK_MODULES_H__
+
+#include <gtk/gtksettings.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Functions for use within GTK+
+ */
+gchar * _gtk_find_module        (const gchar *name,
+			         const gchar *type);
+gchar **_gtk_get_module_path    (const gchar *type);
+
+void    _gtk_modules_init             (gint          argc,
+				       gchar       **argv,
+				       const gchar  *gtk_modules_args);
+void    _gtk_modules_settings_changed (GtkSettings  *settings, 
+				       const gchar  *modules);
+
+typedef void	 (*GtkModuleInitFunc)        (gint	  *argc,
+					      gchar      ***argv);
+typedef void	 (*GtkModuleDisplayInitFunc) (GdkDisplay   *display);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GTK_MODULES_H__ */
--- /dev/null	2004-07-29 15:44:00.000000000 -0400
+++ gtk/gtkmodules.c	2004-08-31 00:17:26.295503478 -0400
@@ -0,0 +1,489 @@
+/* GTK - The GIMP Toolkit
+ * Copyright 1998-2002 Tim Janik, Red Hat, Inc., and others.
+ * Copyright (C) 2003 Alex Graveley
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "gtkmodules.h"
+#include "gtksettings.h"
+#include "gtkdebug.h"
+
+#include <string.h>
+#include <gmodule.h>
+#include <pango/pango-utils.h>	/* For pango_split_file_list */
+
+typedef struct _GtkModuleInfo GtkModuleInfo;
+struct _GtkModuleInfo
+{
+  GModule                 *module;
+  gint                     ref_count;
+  GtkModuleInitFunc        init_func;
+  GtkModuleDisplayInitFunc display_init_func;
+  GSList                  *names;
+};
+
+static GSList *gtk_modules = NULL;
+
+static gboolean default_display_opened = FALSE;
+
+/* Saved argc, argv for delayed module initialization
+ */
+static gint    gtk_argc = 0;
+static gchar **gtk_argv = NULL;
+
+static gchar **
+get_module_path (void)
+{
+  const gchar *module_path_env;
+  const gchar *exe_prefix;
+  const gchar *home_dir;
+  gchar *home_gtk_dir = NULL;
+  gchar *module_path;
+  gchar *default_dir;
+  static gchar **result = NULL;
+
+  if (result)
+    return result;
+
+  home_dir = g_get_home_dir();
+  if (home_dir)
+    home_gtk_dir = g_build_filename (home_dir, ".gtk-2.0", NULL);
+
+  module_path_env = g_getenv ("GTK_PATH");
+  exe_prefix = g_getenv ("GTK_EXE_PREFIX");
+
+  if (exe_prefix)
+    default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", NULL);
+  else
+    default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", NULL);
+
+  if (module_path_env && home_gtk_dir)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+				module_path_env, home_gtk_dir, default_dir, NULL);
+  else if (module_path_env)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+				module_path_env, default_dir, NULL);
+  else if (home_gtk_dir)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+				home_gtk_dir, default_dir, NULL);
+  else
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+				default_dir, NULL);
+
+  g_free (home_gtk_dir);
+  g_free (default_dir);
+
+  result = pango_split_file_list (module_path);
+  g_free (module_path);
+
+  return result;
+}
+
+/**
+ * _gtk_get_module_path:
+ * @type: the type of the module, for instance 'modules', 'engines', immodules'
+ * 
+ * Determines the search path for a particular type of module.
+ * 
+ * Return value: the search path for the module type. Free with g_strfreev().
+ **/
+gchar **
+_gtk_get_module_path (const gchar *type)
+{
+  gchar **paths = get_module_path();
+  gchar **path;
+  gchar **result;
+  gint count = 0;
+
+  for (path = paths; *path; path++)
+    count++;
+
+  result = g_new (gchar *, count * 4 + 1);
+
+  count = 0;
+  for (path = get_module_path (); *path; path++)
+    {
+      gint use_version, use_host;
+      
+      for (use_version = TRUE; use_version >= FALSE; use_version--)
+	for (use_host = TRUE; use_host >= FALSE; use_host--)
+	  {
+	    gchar *tmp_dir;
+	    
+	    if (use_version && use_host)
+	      tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, GTK_HOST, type, NULL);
+	    else if (use_version)
+	      tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, type, NULL);
+	    else if (use_host)
+	      tmp_dir = g_build_filename (*path, GTK_HOST, type, NULL);
+	    else
+	      tmp_dir = g_build_filename (*path, type, NULL);
+
+	    result[count++] = tmp_dir;
+	  }
+    }
+
+  result[count++] = NULL;
+
+  return result;
+}
+
+/* Like g_module_path, but use .la as the suffix
+ */
+static gchar*
+module_build_la_path (const gchar *directory,
+		      const gchar *module_name)
+{
+  gchar *filename;
+  gchar *result;
+	
+  if (strncmp (module_name, "lib", 3) == 0)
+    filename = (gchar *)module_name;
+  else
+    filename =  g_strconcat ("lib", module_name, ".la", NULL);
+
+  if (directory && *directory)
+    result = g_build_filename (directory, filename, NULL);
+  else
+    result = g_strdup (filename);
+
+  if (filename != module_name)
+    g_free (filename);
+
+  return result;
+}
+
+/**
+ * _gtk_find_module:
+ * @name: the name of the module
+ * @type: the type of the module, for instance 'modules', 'engines', immodules'
+ * 
+ * Looks for a dynamically module named @name of type @type in the standard GTK+
+ *  module search path.
+ * 
+ * Return value: the pathname to the found module, or %NULL if it wasn't found.
+ *  Free with g_free().
+ **/
+gchar *
+_gtk_find_module (const gchar *name,
+		  const gchar *type)
+{
+  gchar **paths;
+  gchar **path;
+  gchar *module_name = NULL;
+
+  if (g_path_is_absolute (name))
+    return g_strdup (name);
+
+  paths = _gtk_get_module_path (type);
+  for (path = paths; *path; path++)
+    {
+      gchar *tmp_name;
+
+      tmp_name = g_module_build_path (*path, name);
+      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
+	{
+	  module_name = tmp_name;
+	  goto found;
+	}
+      g_free(tmp_name);
+
+      tmp_name = module_build_la_path (*path, name);
+      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
+	{
+	  module_name = tmp_name;
+	  goto found;
+	}
+      g_free(tmp_name);
+    }
+
+ found:
+  g_strfreev (paths);
+  return module_name;
+}
+
+static GModule *
+find_module (const gchar *name)
+{
+  GModule *module;
+  gchar *module_name;
+
+  module_name = _gtk_find_module (name, "modules");
+  if (!module_name)
+    {
+      /* As last resort, try loading without an absolute path (using system
+       * library path)
+       */
+      module_name = g_module_build_path (NULL, name);
+    }
+
+  module = g_module_open (module_name, G_MODULE_BIND_LAZY);
+  g_free(module_name);
+
+  return module;
+}
+
+static GSList *
+load_module (GSList      *module_list,
+	     const gchar *name)
+{
+  GtkModuleInitFunc modinit_func = NULL;
+  GtkModuleInfo *info;
+  GModule *module = NULL;
+  GSList *l;
+  
+  if (g_module_supported ())
+    {
+      for (l = gtk_modules; l; l = l->next)
+	{
+	  info = l->data;
+	  if (g_slist_find_custom (info->names, 
+				   (gconstpointer) name, 
+				   (GCompareFunc)strcmp))
+	    {
+	      info->ref_count++;
+	      module = info->module;
+	      modinit_func = info->init_func;
+
+	      break;
+	    }
+	}
+
+      if (!module)
+	{
+	  module = find_module (name);
+
+	  if (module &&
+	      g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
+	      modinit_func)
+	    {
+	      info = (GtkModuleInfo *) g_slist_find (gtk_modules, 
+						     (gconstpointer) module);
+	      if (!info)
+		{
+		  g_module_make_resident (module);
+		  info = g_new0 (GtkModuleInfo, 1);
+		  
+		  info->names = g_slist_prepend (info->names, g_strdup (name));
+		  info->module = module;
+		  info->ref_count = 1;
+		  info->init_func = modinit_func;
+		  g_module_symbol (module, "gtk_module_display_init",
+				   (gpointer *) &info->display_init_func);
+		  
+		  gtk_modules = g_slist_prepend (gtk_modules, info);
+
+		  if (default_display_opened && !info->display_init_func)
+		    (* info->init_func) (&gtk_argc, &gtk_argv);
+
+		  /* iterate opened displays for modules supporting display init */
+		  if (info->display_init_func) 
+		    {
+		      GSList *displays, *iter; 		  
+		      displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
+		      for (iter = displays; iter; iter = iter->next)
+			{
+			  GdkDisplay *display = iter->data;
+			  (* info->display_init_func) (display);
+			}
+		      g_slist_free (displays);
+		    }
+		}
+	      else
+		{
+		  GTK_NOTE (MODULES, g_print ("Reloading module: %s\n", name));
+		  
+		  if (!g_slist_find_custom (info->names, 
+					    (gconstpointer) name, 
+					    (GCompareFunc) strcmp))
+		    info->names = g_slist_prepend (info->names, g_strdup (name));
+		  info->ref_count++;
+		  /* FIXME: keep list of names */
+		  g_module_close (module);
+		  module = NULL;
+		}
+	    }
+	}
+    }
+
+  if (!modinit_func)
+    {
+      g_message ("Failed to load module \"%s\": %s",
+		 module ? g_module_name (module) : name,
+		 g_module_error ());
+      if (module)
+	g_module_close (module);
+    }
+  else
+    module_list = g_slist_prepend (module_list, info);
+  
+  return module_list;
+}
+
+
+static void
+gtk_module_info_unref (GtkModuleInfo *info)
+{
+  GSList *l;
+
+  info->ref_count--;
+
+  if (info->ref_count == 0) 
+    {
+      GTK_NOTE (MODULES, 
+		g_print ("Unloading module: %s", g_module_name (info->module)));
+
+      gtk_modules = g_slist_remove (gtk_modules, info);
+      g_module_close (info->module);
+      for (l = info->names; l; l = l->next)
+	g_free (l->data);
+      g_slist_free (info->names);
+      g_free (info);
+    }
+}
+
+static GSList *
+load_modules (const char *module_str)
+{
+  gchar **module_names;
+  GSList *module_list = NULL;
+  gint i;
+
+  GTK_NOTE (MODULES, g_print ("Loading module list: %s", module_str));
+
+  module_names = pango_split_file_list (module_str);
+  for (i = 0; module_names[i]; i++) 
+    module_list = load_module (module_list, module_names[i]);
+
+  module_list = g_slist_reverse (module_list);
+  g_strfreev (module_names);
+
+  return module_list;
+}
+
+static void
+default_display_notify_cb (GdkDisplayManager *display_manager)
+{
+  GSList *slist;
+
+  /* Initialize non-multihead-aware modules when the
+   * default display is first set to a non-NULL value.
+   */
+
+  if (!gdk_display_get_default () || default_display_opened)
+    return;
+
+  default_display_opened = TRUE;
+
+  for (slist = gtk_modules; slist; slist = slist->next)
+    {
+      if (slist->data)
+	{
+	  GtkModuleInfo *info = slist->data;
+
+	  if (!info->display_init_func)
+	    (* info->init_func) (&gtk_argc, &gtk_argv);
+	}
+    }
+}
+
+static void
+display_opened_cb (GdkDisplayManager *display_manager,
+		   GdkDisplay        *display)
+{
+  GSList *slist;
+  
+  for (slist = gtk_modules; slist; slist = slist->next)
+    {
+      if (slist->data)
+	{
+	  GtkModuleInfo *info = slist->data;
+
+	  if (info->display_init_func)
+	    (* info->display_init_func) (display);
+	}
+    }
+}
+
+void
+_gtk_modules_init (gint         argc, 
+		   gchar      **argv, 
+		   const gchar *gtk_modules_args)
+{
+  GdkDisplayManager *display_manager;
+  gint i;
+
+  for (i = 0; i < gtk_argc; i++)
+    g_free (gtk_argv [i]);
+  g_free (gtk_argv);
+
+  /* store argc and argv for later use in mod initialization */
+  gtk_argc = argc;
+  gtk_argv = g_malloc ((argc + 1) * sizeof (char*));
+  for (i = 0; i < gtk_argc; i++)
+    gtk_argv [i] = g_strdup (argv [i]);
+  gtk_argv [argc] = NULL;
+
+  display_manager = gdk_display_manager_get ();
+  g_signal_connect (display_manager, "notify::default-display",
+		    G_CALLBACK (default_display_notify_cb), 
+		    NULL);
+  g_signal_connect (display_manager, "display-opened",
+		    G_CALLBACK (display_opened_cb), 
+		    NULL);
+  g_slist_free (load_modules (gtk_modules_args));
+}
+
+static void
+settings_destroy_notify (gpointer data)
+{
+  GSList *iter, *modules = data;
+
+  for (iter = modules; iter; iter = iter->next) 
+    {
+      GtkModuleInfo *info = iter->data;
+      gtk_module_info_unref (info);
+    }
+  g_slist_free (modules);
+}
+
+void
+_gtk_modules_settings_changed (GtkSettings *settings, 
+			       const gchar *modules)
+{
+  GSList *new_modules = NULL, *old_modules = NULL, *iter;
+
+  /* load/ref before unreffing existing */
+  if (modules && modules[0])
+    new_modules = load_modules (modules);
+
+  old_modules = g_object_get_data (G_OBJECT (settings), "gtk-modules");
+
+  for (iter = old_modules; iter; iter = iter->next) 
+    {
+      GtkModuleInfo *info = iter->data;
+      gtk_module_info_unref (info);
+    }
+  g_slist_free (old_modules);
+
+  g_object_set_data_full (G_OBJECT (settings),
+			  "gtk-modules",
+			  new_modules,
+			  settings_destroy_notify);
+}
