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) (>k_argc, >k_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) (>k_argc, >k_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