1 /* GTK - The GIMP Toolkit
2  * Copyright 1998-2002 Tim Janik, Red Hat, Inc., and others.
3  * Copyright (C) 2003 Alex Graveley
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "config.h"
20 
21 #include <string.h>
22 
23 #include "gtkmodules.h"
24 #include "gtksettings.h"
25 #include "gtkdebug.h"
26 #include "gtkprivate.h"
27 #include "gtkmodulesprivate.h"
28 #include "gtkintl.h"
29 #include "gtkutilsprivate.h"
30 
31 #include <gmodule.h>
32 
33 typedef struct _GtkModuleInfo GtkModuleInfo;
34 struct _GtkModuleInfo
35 {
36   GModule                 *module;
37   gint                     ref_count;
38   GtkModuleInitFunc        init_func;
39   GtkModuleDisplayInitFunc display_init_func;
40   GSList                  *names;
41 };
42 
43 static GSList *gtk_modules = NULL;
44 
45 static gboolean default_display_opened = FALSE;
46 
47 /* Saved argc, argv for delayed module initialization
48  */
49 static gint    gtk_argc = 0;
50 static gchar **gtk_argv = NULL;
51 
52 static gchar **
get_module_path(void)53 get_module_path (void)
54 {
55   const gchar *module_path_env;
56   const gchar *exe_prefix;
57   gchar *module_path;
58   gchar *default_dir;
59   static gchar **result = NULL;
60 
61   if (result)
62     return result;
63 
64   module_path_env = g_getenv ("GTK_PATH");
65   exe_prefix = g_getenv ("GTK_EXE_PREFIX");
66 
67   if (exe_prefix)
68     default_dir = g_build_filename (exe_prefix, "lib", "gtk-3.0", NULL);
69   else
70     default_dir = g_build_filename (_gtk_get_libdir (), "gtk-3.0", NULL);
71 
72   if (module_path_env)
73     module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
74 				module_path_env, default_dir, NULL);
75   else
76     module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
77 				default_dir, NULL);
78 
79   g_free (default_dir);
80 
81   result = gtk_split_file_list (module_path);
82   g_free (module_path);
83 
84   return result;
85 }
86 
87 /**
88  * _gtk_get_module_path:
89  * @type: the type of the module, for instance 'modules', 'engines', immodules'
90  *
91  * Determines the search path for a particular type of module.
92  *
93  * Returns: the search path for the module type. Free with g_strfreev().
94  **/
95 gchar **
_gtk_get_module_path(const gchar * type)96 _gtk_get_module_path (const gchar *type)
97 {
98   gchar **paths = get_module_path();
99   gchar **path;
100   gchar **result;
101   gint count = 0;
102 
103   for (path = paths; *path; path++)
104     count++;
105 
106   result = g_new (gchar *, count * 4 + 1);
107 
108   count = 0;
109   for (path = get_module_path (); *path; path++)
110     {
111       gint use_version, use_host;
112 
113       for (use_version = TRUE; use_version >= FALSE; use_version--)
114 	for (use_host = TRUE; use_host >= FALSE; use_host--)
115 	  {
116 	    gchar *tmp_dir;
117 
118 	    if (use_version && use_host)
119 	      tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, GTK_HOST, type, NULL);
120 	    else if (use_version)
121 	      tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, type, NULL);
122 	    else if (use_host)
123 	      tmp_dir = g_build_filename (*path, GTK_HOST, type, NULL);
124 	    else
125 	      tmp_dir = g_build_filename (*path, type, NULL);
126 
127 	    result[count++] = tmp_dir;
128 	  }
129     }
130 
131   result[count++] = NULL;
132 
133   return result;
134 }
135 
136 /* Like g_module_path, but use .la as the suffix
137  */
138 static gchar*
module_build_la_path(const gchar * directory,const gchar * module_name)139 module_build_la_path (const gchar *directory,
140 		      const gchar *module_name)
141 {
142   gchar *filename;
143   gchar *result;
144 
145   if (strncmp (module_name, "lib", 3) == 0)
146     filename = (gchar *)module_name;
147   else
148     filename =  g_strconcat ("lib", module_name, ".la", NULL);
149 
150   if (directory && *directory)
151     result = g_build_filename (directory, filename, NULL);
152   else
153     result = g_strdup (filename);
154 
155   if (filename != module_name)
156     g_free (filename);
157 
158   return result;
159 }
160 
161 /**
162  * _gtk_find_module:
163  * @name: the name of the module
164  * @type: the type of the module, for instance 'modules', 'engines', immodules'
165  *
166  * Looks for a dynamically module named @name of type @type in the standard GTK+
167  *  module search path.
168  *
169  * Returns: the pathname to the found module, or %NULL if it wasn’t found.
170  *  Free with g_free().
171  **/
172 gchar *
_gtk_find_module(const gchar * name,const gchar * type)173 _gtk_find_module (const gchar *name,
174 		  const gchar *type)
175 {
176   gchar **paths;
177   gchar **path;
178   gchar *module_name = NULL;
179 
180   if (g_path_is_absolute (name))
181     return g_strdup (name);
182 
183   paths = _gtk_get_module_path (type);
184   for (path = paths; *path; path++)
185     {
186       gchar *tmp_name;
187 
188       tmp_name = g_module_build_path (*path, name);
189       if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
190 	{
191 	  module_name = tmp_name;
192 	  goto found;
193 	}
194       g_free(tmp_name);
195 
196       tmp_name = module_build_la_path (*path, name);
197       if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
198 	{
199 	  module_name = tmp_name;
200 	  goto found;
201 	}
202       g_free(tmp_name);
203     }
204 
205  found:
206   g_strfreev (paths);
207   return module_name;
208 }
209 
210 static GModule *
find_module(const gchar * name)211 find_module (const gchar *name)
212 {
213   GModule *module;
214   gchar *module_name;
215 
216   module_name = _gtk_find_module (name, "modules");
217   if (!module_name)
218     {
219       /* As last resort, try loading without an absolute path (using system
220        * library path)
221        */
222       module_name = g_module_build_path (NULL, name);
223     }
224 
225   module = g_module_open (module_name, G_MODULE_BIND_LOCAL | G_MODULE_BIND_LAZY);
226 
227   if (_gtk_module_has_mixed_deps (module))
228     {
229       g_warning ("GTK+ module %s cannot be loaded.\n"
230                  "GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported.", module_name);
231       g_module_close (module);
232       module = NULL;
233     }
234 
235   g_free (module_name);
236 
237   return module;
238 }
239 
240 static gint
cmp_module(GtkModuleInfo * info,GModule * module)241 cmp_module (GtkModuleInfo *info,
242 	    GModule       *module)
243 {
244   return info->module != module;
245 }
246 
247 static gboolean
module_is_blacklisted(const gchar * name,gboolean verbose)248 module_is_blacklisted (const gchar *name,
249                        gboolean     verbose)
250 {
251   if (g_str_equal (name, "gail") ||
252       g_str_equal (name, "atk-bridge"))
253     {
254       if (verbose)
255         g_message ("Not loading module \"%s\": The functionality is provided by GTK natively. Please try to not load it.", name);
256 
257       return TRUE;
258     }
259 
260   return FALSE;
261 }
262 
263 static GSList *
load_module(GSList * module_list,const gchar * name)264 load_module (GSList      *module_list,
265 	     const gchar *name)
266 {
267   GtkModuleInitFunc modinit_func;
268   gpointer modinit_func_ptr;
269   GtkModuleInfo *info = NULL;
270   GModule *module = NULL;
271   GSList *l;
272   gboolean success = FALSE;
273 
274   if (g_module_supported ())
275     {
276       for (l = gtk_modules; l; l = l->next)
277 	{
278 	  info = l->data;
279 	  if (g_slist_find_custom (info->names, name,
280 				   (GCompareFunc)strcmp))
281 	    {
282 	      info->ref_count++;
283 
284 	      success = TRUE;
285               break;
286 	    }
287           info = NULL;
288 	}
289 
290       if (!success)
291 	{
292 	  module = find_module (name);
293 
294 	  if (module)
295 	    {
296               /* Do the check this late so we only warn about existing modules,
297                * not old modules that are still in the modules path. */
298               if (module_is_blacklisted (name, TRUE))
299                 {
300                   modinit_func = NULL;
301                   success = TRUE;
302                 }
303               else if (g_module_symbol (module, "gtk_module_init", &modinit_func_ptr))
304 		modinit_func = modinit_func_ptr;
305 	      else
306 		modinit_func = NULL;
307 
308 	      if (!modinit_func)
309 		g_module_close (module);
310 	      else
311 		{
312 		  GSList *temp;
313 
314 		  success = TRUE;
315 		  info = NULL;
316 
317 		  temp = g_slist_find_custom (gtk_modules, module,
318 			(GCompareFunc)cmp_module);
319 		  if (temp != NULL)
320 			info = temp->data;
321 
322 		  if (!info)
323 		    {
324 		      info = g_new0 (GtkModuleInfo, 1);
325 
326 		      info->names = g_slist_prepend (info->names, g_strdup (name));
327 		      info->module = module;
328 		      info->ref_count = 1;
329 		      info->init_func = modinit_func;
330 		      g_module_symbol (module, "gtk_module_display_init",
331 				       (gpointer *) &info->display_init_func);
332 
333 		      gtk_modules = g_slist_append (gtk_modules, info);
334 
335 		      /* display_init == NULL indicates a non-multihead aware module.
336 		       * For these, we delay the call to init_func until first display is
337 		       * opened, see default_display_notify_cb().
338 		       * For multihead aware modules, we call init_func immediately,
339 		       * and also call display_init_func on all opened displays.
340 		       */
341 		      if (default_display_opened || info->display_init_func)
342 			(* info->init_func) (&gtk_argc, &gtk_argv);
343 
344 		      if (info->display_init_func)
345 			{
346 			  GSList *displays, *iter;
347 			  displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
348 			  for (iter = displays; iter; iter = iter->next)
349 			    {
350 			      GdkDisplay *display = iter->data;
351 			  (* info->display_init_func) (display);
352 			    }
353 			  g_slist_free (displays);
354 			}
355 		    }
356 		  else
357 		    {
358 		      GTK_NOTE (MODULES, g_message ("Module already loaded, ignoring: %s", name));
359 		      info->names = g_slist_prepend (info->names, g_strdup (name));
360 		      info->ref_count++;
361 		      /* remove new reference count on module, we already have one */
362 		      g_module_close (module);
363 		    }
364 		}
365 	    }
366 	}
367     }
368 
369   if (success && info)
370     {
371       if (!g_slist_find (module_list, info))
372 	{
373 	  module_list = g_slist_prepend (module_list, info);
374 	}
375     }
376   else
377     {
378       if (!module_is_blacklisted (name, FALSE))
379         {
380           const gchar *error = g_module_error ();
381 
382           g_message ("Failed to load module \"%s\"%s%s",
383                      name, error ? ": " : "", error ? error : "");
384         }
385     }
386 
387   return module_list;
388 }
389 
390 
391 static void
gtk_module_info_unref(GtkModuleInfo * info)392 gtk_module_info_unref (GtkModuleInfo *info)
393 {
394   GSList *l;
395 
396   info->ref_count--;
397 
398   if (info->ref_count == 0)
399     {
400       GTK_NOTE (MODULES,
401 		g_message ("Unloading module: %s", g_module_name (info->module)));
402 
403       gtk_modules = g_slist_remove (gtk_modules, info);
404       g_module_close (info->module);
405       for (l = info->names; l; l = l->next)
406 	g_free (l->data);
407       g_slist_free (info->names);
408       g_free (info);
409     }
410 }
411 
412 static GSList *
load_modules(const char * module_str)413 load_modules (const char *module_str)
414 {
415   gchar **module_names;
416   GSList *module_list = NULL;
417   gint i;
418 
419   GTK_NOTE (MODULES, g_message ("Loading module list: %s", module_str));
420 
421   module_names = gtk_split_file_list (module_str);
422   for (i = 0; module_names[i]; i++)
423     module_list = load_module (module_list, module_names[i]);
424 
425   module_list = g_slist_reverse (module_list);
426   g_strfreev (module_names);
427 
428   return module_list;
429 }
430 
431 static void
default_display_notify_cb(GdkDisplayManager * display_manager)432 default_display_notify_cb (GdkDisplayManager *display_manager)
433 {
434   GSList *slist;
435 
436   /* Initialize non-multihead-aware modules when the
437    * default display is first set to a non-NULL value.
438    */
439 
440   if (!gdk_display_get_default () || default_display_opened)
441     return;
442 
443   default_display_opened = TRUE;
444 
445   for (slist = gtk_modules; slist; slist = slist->next)
446     {
447       if (slist->data)
448 	{
449 	  GtkModuleInfo *info = slist->data;
450 
451 	  if (!info->display_init_func)
452 	    (* info->init_func) (&gtk_argc, &gtk_argv);
453 	}
454     }
455 }
456 
457 static void
display_closed_cb(GdkDisplay * display,gboolean is_error)458 display_closed_cb (GdkDisplay *display,
459 		   gboolean    is_error)
460 {
461   GdkScreen *screen;
462   GtkSettings *settings;
463 
464   screen = gdk_display_get_default_screen (display);
465   settings = gtk_settings_get_for_screen (screen);
466   if (settings)
467     g_object_set_data_full (G_OBJECT (settings),
468 			    I_("gtk-modules"),
469 			    NULL, NULL);
470 }
471 
472 
473 static void
display_opened_cb(GdkDisplayManager * display_manager,GdkDisplay * display)474 display_opened_cb (GdkDisplayManager *display_manager,
475 		   GdkDisplay        *display)
476 {
477   GValue value = G_VALUE_INIT;
478   GSList *slist;
479   GdkScreen *screen;
480   GtkSettings *settings;
481 
482   for (slist = gtk_modules; slist; slist = slist->next)
483     {
484       if (slist->data)
485 	{
486 	  GtkModuleInfo *info = slist->data;
487 
488 	  if (info->display_init_func)
489 	    (* info->display_init_func) (display);
490 	}
491     }
492 
493   g_value_init (&value, G_TYPE_STRING);
494   screen = gdk_display_get_default_screen (display);
495 
496   if (gdk_screen_get_setting (screen, "gtk-modules", &value))
497     {
498       settings = gtk_settings_get_for_screen (screen);
499       _gtk_modules_settings_changed (settings, g_value_get_string (&value));
500       g_value_unset (&value);
501     }
502 
503   /* Since closing display doesn't actually release the resources yet,
504    * we have to connect to the ::closed signal.
505    */
506   g_signal_connect (display, "closed", G_CALLBACK (display_closed_cb), NULL);
507 }
508 
509 void
_gtk_modules_init(gint * argc,gchar *** argv,const gchar * gtk_modules_args)510 _gtk_modules_init (gint        *argc,
511 		   gchar     ***argv,
512 		   const gchar *gtk_modules_args)
513 {
514   GdkDisplayManager *display_manager;
515   gint i;
516 
517   g_assert (gtk_argv == NULL);
518 
519   if (argc && argv)
520     {
521       /* store argc and argv for later use in mod initialization */
522       gtk_argc = *argc;
523       gtk_argv = g_new (gchar *, *argc + 1);
524       for (i = 0; i < gtk_argc; i++)
525 	gtk_argv [i] = g_strdup ((*argv) [i]);
526       gtk_argv [*argc] = NULL;
527     }
528 
529   display_manager = gdk_display_manager_get ();
530   default_display_opened = gdk_display_get_default () != NULL;
531   g_signal_connect (display_manager, "notify::default-display",
532                     G_CALLBACK (default_display_notify_cb),
533                     NULL);
534   g_signal_connect (display_manager, "display-opened",
535                     G_CALLBACK (display_opened_cb),
536                     NULL);
537 
538   if (gtk_modules_args)
539     {
540       /* Modules specified in the GTK_MODULES environment variable
541        * or on the command line are always loaded, so we'll just leak
542        * the refcounts.
543        */
544       g_slist_free (load_modules (gtk_modules_args));
545     }
546 }
547 
548 static void
settings_destroy_notify(gpointer data)549 settings_destroy_notify (gpointer data)
550 {
551   GSList *iter, *modules = data;
552 
553   for (iter = modules; iter; iter = iter->next)
554     {
555       GtkModuleInfo *info = iter->data;
556       gtk_module_info_unref (info);
557     }
558   g_slist_free (modules);
559 }
560 
561 void
_gtk_modules_settings_changed(GtkSettings * settings,const gchar * modules)562 _gtk_modules_settings_changed (GtkSettings *settings,
563 			       const gchar *modules)
564 {
565   GSList *new_modules = NULL;
566 
567   GTK_NOTE (MODULES, g_message ("gtk-modules setting changed to: %s", modules));
568 
569   /* load/ref before unreffing existing */
570   if (modules && modules[0])
571     new_modules = load_modules (modules);
572 
573   g_object_set_data_full (G_OBJECT (settings),
574 			  I_("gtk-modules"),
575 			  new_modules,
576 			  settings_destroy_notify);
577 }
578 
579 /* Return TRUE if module_to_check causes version conflicts.
580  * If module_to_check is NULL, check the main module.
581  */
582 gboolean
_gtk_module_has_mixed_deps(GModule * module_to_check)583 _gtk_module_has_mixed_deps (GModule *module_to_check)
584 {
585   GModule *module;
586   gpointer func;
587   gboolean result;
588 
589   if (!module_to_check)
590     module = g_module_open (NULL, 0);
591   else
592     module = module_to_check;
593 
594   if (g_module_symbol (module, "gtk_progress_get_type", &func))
595     result = TRUE;
596   else
597     result = FALSE;
598 
599   if (!module_to_check)
600     g_module_close (module);
601 
602   return result;
603 }
604