 b1d55f2c85
			
		
	
	b1d55f2c85
	
	
	
		
			
			GTK caches the settings per display in a static `GArray`, keeping a
reference to the `GdkDisplay` as the key.
However, when closing the display, the corresponding entry is not
removed from the cache in `GtkSettings`.
So when reopening again a `GdkDisplay`, if the new address matches one
of the previously closed display, the cache will return the existing
`GtkSettings` from the cache, which still holds a reference to the old
`GdkScreen` which was freed along the `GdkDisplay`.
To avoid the issue, make sure to remove the `GdkDisplay` and
corresponding `GdkSettings` when closing the `GdkDisplay`.
Also, care must be taken not to recreate the `GdkSettings` and re-add
the `GdkDisplay` to the cache once the display is closed, and make sure
callers of `gtk_settings_get_for_display()` can deal with a returned
value being `NULL` if the display is closed.
Fixes: commit 360a3c1690 - "Use a cheaper way to store settings per
display"
		
	
		
			
				
	
	
		
			604 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			604 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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, see <http://www.gnu.org/licenses/>.
 | ||
|  */
 | ||
| 
 | ||
| #include "config.h"
 | ||
| 
 | ||
| #include <string.h>
 | ||
| 
 | ||
| #include "gtkmodules.h"
 | ||
| #include "gtksettings.h"
 | ||
| #include "gtkdebug.h"
 | ||
| #include "gtkprivate.h"
 | ||
| #include "gtkmodulesprivate.h"
 | ||
| #include "gtkintl.h"
 | ||
| #include "gtkutilsprivate.h"
 | ||
| 
 | ||
| #include <gmodule.h>
 | ||
| 
 | ||
| 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;
 | ||
|   gchar *module_path;
 | ||
|   gchar *default_dir;
 | ||
|   static gchar **result = NULL;
 | ||
| 
 | ||
|   if (result)
 | ||
|     return result;
 | ||
| 
 | ||
|   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-3.0", NULL);
 | ||
|   else
 | ||
|     default_dir = g_build_filename (_gtk_get_libdir (), "gtk-3.0", NULL);
 | ||
| 
 | ||
|   if (module_path_env)
 | ||
|     module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
 | ||
| 				module_path_env, default_dir, NULL);
 | ||
|   else
 | ||
|     module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
 | ||
| 				default_dir, NULL);
 | ||
| 
 | ||
|   g_free (default_dir);
 | ||
| 
 | ||
|   result = gtk_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.
 | ||
|  * 
 | ||
|  * Returns: 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.
 | ||
|  * 
 | ||
|  * Returns: 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_LOCAL | G_MODULE_BIND_LAZY);
 | ||
| 
 | ||
|   if (_gtk_module_has_mixed_deps (module))
 | ||
|     {
 | ||
|       g_warning ("GTK+ module %s cannot be loaded.\n"
 | ||
|                  "GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported.", module_name);
 | ||
|       g_module_close (module);
 | ||
|       module = NULL;
 | ||
|     }
 | ||
| 
 | ||
|   g_free (module_name);
 | ||
| 
 | ||
|   return module;
 | ||
| }
 | ||
| 
 | ||
| static gint
 | ||
| cmp_module (GtkModuleInfo *info,
 | ||
| 	    GModule       *module)
 | ||
| {
 | ||
|   return info->module != module;
 | ||
| }
 | ||
| 
 | ||
| static gboolean
 | ||
| module_is_blacklisted (const gchar *name,
 | ||
|                        gboolean     verbose)
 | ||
| {
 | ||
|   if (g_str_equal (name, "gail") ||
 | ||
|       g_str_equal (name, "atk-bridge"))
 | ||
|     {
 | ||
|       if (verbose)
 | ||
|         g_message ("Not loading module \"%s\": The functionality is provided by GTK natively. Please try to not load it.", name);
 | ||
| 
 | ||
|       return TRUE;
 | ||
|     }
 | ||
| 
 | ||
|   return FALSE;
 | ||
| }
 | ||
| 
 | ||
| static GSList *
 | ||
| load_module (GSList      *module_list,
 | ||
| 	     const gchar *name)
 | ||
| {
 | ||
|   GtkModuleInitFunc modinit_func;
 | ||
|   gpointer modinit_func_ptr;
 | ||
|   GtkModuleInfo *info = NULL;
 | ||
|   GModule *module = NULL;
 | ||
|   GSList *l;
 | ||
|   gboolean success = FALSE;
 | ||
|   
 | ||
|   if (g_module_supported ())
 | ||
|     {
 | ||
|       for (l = gtk_modules; l; l = l->next)
 | ||
| 	{
 | ||
| 	  info = l->data;
 | ||
| 	  if (g_slist_find_custom (info->names, name,
 | ||
| 				   (GCompareFunc)strcmp))
 | ||
| 	    {
 | ||
| 	      info->ref_count++;
 | ||
| 	      
 | ||
| 	      success = TRUE;
 | ||
|               break;
 | ||
| 	    }
 | ||
|           info = NULL;
 | ||
| 	}
 | ||
| 
 | ||
|       if (!success)
 | ||
| 	{
 | ||
| 	  module = find_module (name);
 | ||
| 
 | ||
| 	  if (module)
 | ||
| 	    {
 | ||
|               /* Do the check this late so we only warn about existing modules,
 | ||
|                * not old modules that are still in the modules path. */
 | ||
|               if (module_is_blacklisted (name, TRUE))
 | ||
|                 {
 | ||
|                   modinit_func = NULL;
 | ||
|                   success = TRUE;
 | ||
|                 }
 | ||
|               else if (g_module_symbol (module, "gtk_module_init", &modinit_func_ptr))
 | ||
| 		modinit_func = modinit_func_ptr;
 | ||
| 	      else
 | ||
| 		modinit_func = NULL;
 | ||
| 
 | ||
| 	      if (!modinit_func)
 | ||
| 		g_module_close (module);
 | ||
| 	      else
 | ||
| 		{
 | ||
| 		  GSList *temp;
 | ||
| 
 | ||
| 		  success = TRUE;
 | ||
| 		  info = NULL;
 | ||
| 
 | ||
| 		  temp = g_slist_find_custom (gtk_modules, module,
 | ||
| 			(GCompareFunc)cmp_module);
 | ||
| 		  if (temp != NULL)
 | ||
| 			info = temp->data;
 | ||
| 
 | ||
| 		  if (!info)
 | ||
| 		    {
 | ||
| 		      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_append (gtk_modules, info);
 | ||
| 		      
 | ||
| 		      /* display_init == NULL indicates a non-multihead aware module.
 | ||
| 		       * For these, we delay the call to init_func until first display is
 | ||
| 		       * opened, see default_display_notify_cb().
 | ||
| 		       * For multihead aware modules, we call init_func immediately,
 | ||
| 		       * and also call display_init_func on all opened displays.
 | ||
| 		       */
 | ||
| 		      if (default_display_opened || info->display_init_func)
 | ||
| 			(* info->init_func) (>k_argc, >k_argv);
 | ||
| 		      
 | ||
| 		      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_message ("Module already loaded, ignoring: %s", name));
 | ||
| 		      info->names = g_slist_prepend (info->names, g_strdup (name));
 | ||
| 		      info->ref_count++;
 | ||
| 		      /* remove new reference count on module, we already have one */
 | ||
| 		      g_module_close (module);
 | ||
| 		    }
 | ||
| 		}
 | ||
| 	    }
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   if (success && info)
 | ||
|     {
 | ||
|       if (!g_slist_find (module_list, info))
 | ||
| 	{
 | ||
| 	  module_list = g_slist_prepend (module_list, info);
 | ||
| 	}
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       if (!module_is_blacklisted (name, FALSE))
 | ||
|         {
 | ||
|           const gchar *error = g_module_error ();
 | ||
| 
 | ||
|           g_message ("Failed to load module \"%s\"%s%s",
 | ||
|                      name, error ? ": " : "", error ? error : "");
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|   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_message ("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_message ("Loading module list: %s", module_str));
 | ||
| 
 | ||
|   module_names = gtk_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) (>k_argc, >k_argv);
 | ||
| 	}
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| static void
 | ||
| display_closed_cb (GdkDisplay *display,
 | ||
| 		   gboolean    is_error)
 | ||
| {
 | ||
|   GdkScreen *screen;
 | ||
|   GtkSettings *settings;
 | ||
| 
 | ||
|   screen = gdk_display_get_default_screen (display);
 | ||
|   settings = gtk_settings_get_for_screen (screen);
 | ||
|   if (settings)
 | ||
|     g_object_set_data_full (G_OBJECT (settings),
 | ||
| 			    I_("gtk-modules"),
 | ||
| 			    NULL, NULL);
 | ||
| }
 | ||
| 		   
 | ||
| 
 | ||
| static void
 | ||
| display_opened_cb (GdkDisplayManager *display_manager,
 | ||
| 		   GdkDisplay        *display)
 | ||
| {
 | ||
|   GValue value = G_VALUE_INIT;
 | ||
|   GSList *slist;
 | ||
|   GdkScreen *screen;
 | ||
|   GtkSettings *settings;
 | ||
| 
 | ||
|   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);
 | ||
| 	}
 | ||
|     }
 | ||
|   
 | ||
|   g_value_init (&value, G_TYPE_STRING);
 | ||
|   screen = gdk_display_get_default_screen (display);
 | ||
| 
 | ||
|   if (gdk_screen_get_setting (screen, "gtk-modules", &value))
 | ||
|     {
 | ||
|       settings = gtk_settings_get_for_screen (screen);
 | ||
|       _gtk_modules_settings_changed (settings, g_value_get_string (&value));
 | ||
|       g_value_unset (&value);
 | ||
|     }
 | ||
| 
 | ||
|   /* Since closing display doesn't actually release the resources yet,
 | ||
|    * we have to connect to the ::closed signal.
 | ||
|    */
 | ||
|   g_signal_connect (display, "closed", G_CALLBACK (display_closed_cb), NULL);
 | ||
| }
 | ||
| 
 | ||
| void
 | ||
| _gtk_modules_init (gint        *argc,
 | ||
| 		   gchar     ***argv,
 | ||
| 		   const gchar *gtk_modules_args)
 | ||
| {
 | ||
|   GdkDisplayManager *display_manager;
 | ||
|   gint i;
 | ||
| 
 | ||
|   g_assert (gtk_argv == NULL);
 | ||
| 
 | ||
|   if (argc && argv)
 | ||
|     {
 | ||
|       /* store argc and argv for later use in mod initialization */
 | ||
|       gtk_argc = *argc;
 | ||
|       gtk_argv = g_new (gchar *, *argc + 1);
 | ||
|       for (i = 0; i < gtk_argc; i++)
 | ||
| 	gtk_argv [i] = g_strdup ((*argv) [i]);
 | ||
|       gtk_argv [*argc] = NULL;
 | ||
|     }
 | ||
| 
 | ||
|   display_manager = gdk_display_manager_get ();
 | ||
|   default_display_opened = gdk_display_get_default () != NULL;
 | ||
|   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);
 | ||
| 
 | ||
|   if (gtk_modules_args)
 | ||
|     {
 | ||
|       /* Modules specified in the GTK_MODULES environment variable
 | ||
|        * or on the command line are always loaded, so we'll just leak
 | ||
|        * the refcounts.
 | ||
|        */
 | ||
|       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;
 | ||
| 
 | ||
|   GTK_NOTE (MODULES, g_message ("gtk-modules setting changed to: %s", modules));
 | ||
| 
 | ||
|   /* load/ref before unreffing existing */
 | ||
|   if (modules && modules[0])
 | ||
|     new_modules = load_modules (modules);
 | ||
| 
 | ||
|   g_object_set_data_full (G_OBJECT (settings),
 | ||
| 			  I_("gtk-modules"),
 | ||
| 			  new_modules,
 | ||
| 			  settings_destroy_notify);
 | ||
| }
 | ||
| 
 | ||
| /* Return TRUE if module_to_check causes version conflicts.
 | ||
|  * If module_to_check is NULL, check the main module.
 | ||
|  */
 | ||
| gboolean
 | ||
| _gtk_module_has_mixed_deps (GModule *module_to_check)
 | ||
| {
 | ||
|   GModule *module;
 | ||
|   gpointer func;
 | ||
|   gboolean result;
 | ||
| 
 | ||
|   if (!module_to_check)
 | ||
|     module = g_module_open (NULL, 0);
 | ||
|   else
 | ||
|     module = module_to_check;
 | ||
| 
 | ||
|   if (g_module_symbol (module, "gtk_progress_get_type", &func))
 | ||
|     result = TRUE;
 | ||
|   else
 | ||
|     result = FALSE;
 | ||
| 
 | ||
|   if (!module_to_check)
 | ||
|     g_module_close (module);
 | ||
| 
 | ||
|   return result;
 | ||
| }
 |