]> Pileus Git - ~andy/gtk/blob - gtk/gtkmodules.c
Really free the list. (#158422, Morten Welinder)
[~andy/gtk] / gtk / gtkmodules.c
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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22
23 #include <string.h>
24
25 #include "gtkmodules.h"
26 #include "gtksettings.h"
27 #include "gtkdebug.h"
28 #include "gtkprivate.h" /* GTK_LIBDIR */
29
30 #include <gmodule.h>
31 #include <pango/pango-utils.h>  /* For pango_split_file_list */
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 **
53 get_module_path (void)
54 {
55   const gchar *module_path_env;
56   const gchar *exe_prefix;
57   const gchar *home_dir;
58   gchar *home_gtk_dir = NULL;
59   gchar *module_path;
60   gchar *default_dir;
61   static gchar **result = NULL;
62
63   if (result)
64     return result;
65
66   home_dir = g_get_home_dir();
67   if (home_dir)
68     home_gtk_dir = g_build_filename (home_dir, ".gtk-2.0", NULL);
69
70   module_path_env = g_getenv ("GTK_PATH");
71   exe_prefix = g_getenv ("GTK_EXE_PREFIX");
72
73   if (exe_prefix)
74     default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", NULL);
75   else
76     default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", NULL);
77
78   if (module_path_env && home_gtk_dir)
79     module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
80                                 module_path_env, home_gtk_dir, default_dir, NULL);
81   else if (module_path_env)
82     module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
83                                 module_path_env, default_dir, NULL);
84   else if (home_gtk_dir)
85     module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
86                                 home_gtk_dir, default_dir, NULL);
87   else
88     module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
89                                 default_dir, NULL);
90
91   g_free (home_gtk_dir);
92   g_free (default_dir);
93
94   result = pango_split_file_list (module_path);
95   g_free (module_path);
96
97   return result;
98 }
99
100 /**
101  * _gtk_get_module_path:
102  * @type: the type of the module, for instance 'modules', 'engines', immodules'
103  * 
104  * Determines the search path for a particular type of module.
105  * 
106  * Return value: the search path for the module type. Free with g_strfreev().
107  **/
108 gchar **
109 _gtk_get_module_path (const gchar *type)
110 {
111   gchar **paths = get_module_path();
112   gchar **path;
113   gchar **result;
114   gint count = 0;
115
116   for (path = paths; *path; path++)
117     count++;
118
119   result = g_new (gchar *, count * 4 + 1);
120
121   count = 0;
122   for (path = get_module_path (); *path; path++)
123     {
124       gint use_version, use_host;
125       
126       for (use_version = TRUE; use_version >= FALSE; use_version--)
127         for (use_host = TRUE; use_host >= FALSE; use_host--)
128           {
129             gchar *tmp_dir;
130             
131             if (use_version && use_host)
132               tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, GTK_HOST, type, NULL);
133             else if (use_version)
134               tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, type, NULL);
135             else if (use_host)
136               tmp_dir = g_build_filename (*path, GTK_HOST, type, NULL);
137             else
138               tmp_dir = g_build_filename (*path, type, NULL);
139
140             result[count++] = tmp_dir;
141           }
142     }
143
144   result[count++] = NULL;
145
146   return result;
147 }
148
149 /* Like g_module_path, but use .la as the suffix
150  */
151 static gchar*
152 module_build_la_path (const gchar *directory,
153                       const gchar *module_name)
154 {
155   gchar *filename;
156   gchar *result;
157         
158   if (strncmp (module_name, "lib", 3) == 0)
159     filename = (gchar *)module_name;
160   else
161     filename =  g_strconcat ("lib", module_name, ".la", NULL);
162
163   if (directory && *directory)
164     result = g_build_filename (directory, filename, NULL);
165   else
166     result = g_strdup (filename);
167
168   if (filename != module_name)
169     g_free (filename);
170
171   return result;
172 }
173
174 /**
175  * _gtk_find_module:
176  * @name: the name of the module
177  * @type: the type of the module, for instance 'modules', 'engines', immodules'
178  * 
179  * Looks for a dynamically module named @name of type @type in the standard GTK+
180  *  module search path.
181  * 
182  * Return value: the pathname to the found module, or %NULL if it wasn't found.
183  *  Free with g_free().
184  **/
185 gchar *
186 _gtk_find_module (const gchar *name,
187                   const gchar *type)
188 {
189   gchar **paths;
190   gchar **path;
191   gchar *module_name = NULL;
192
193   if (g_path_is_absolute (name))
194     return g_strdup (name);
195
196   paths = _gtk_get_module_path (type);
197   for (path = paths; *path; path++)
198     {
199       gchar *tmp_name;
200
201       tmp_name = g_module_build_path (*path, name);
202       if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
203         {
204           module_name = tmp_name;
205           goto found;
206         }
207       g_free(tmp_name);
208
209       tmp_name = module_build_la_path (*path, name);
210       if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
211         {
212           module_name = tmp_name;
213           goto found;
214         }
215       g_free(tmp_name);
216     }
217
218  found:
219   g_strfreev (paths);
220   return module_name;
221 }
222
223 static GModule *
224 find_module (const gchar *name)
225 {
226   GModule *module;
227   gchar *module_name;
228
229   module_name = _gtk_find_module (name, "modules");
230   if (!module_name)
231     {
232       /* As last resort, try loading without an absolute path (using system
233        * library path)
234        */
235       module_name = g_module_build_path (NULL, name);
236     }
237
238   module = g_module_open (module_name, G_MODULE_BIND_LAZY);
239   g_free(module_name);
240
241   return module;
242 }
243
244 static gint
245 cmp_module (GtkModuleInfo *info,
246             GModule       *module)
247 {
248   return info->module != module;
249 }
250
251 static GSList *
252 load_module (GSList      *module_list,
253              const gchar *name)
254 {
255   GtkModuleInitFunc modinit_func;
256   GtkModuleInfo *info = NULL;
257   GModule *module = NULL;
258   GSList *l;
259   gboolean success = FALSE;
260   
261   if (g_module_supported ())
262     {
263       for (l = gtk_modules; l; l = l->next)
264         {
265           info = l->data;
266           if (g_slist_find_custom (info->names, name, 
267                                    (GCompareFunc)strcmp))
268             {
269               info->ref_count++;
270               
271               success = TRUE;
272             }
273         }
274
275       if (!success) 
276         {
277           module = find_module (name);
278
279           if (module)
280             {
281               if (!g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) ||
282                   !modinit_func)
283                 g_module_close (module);
284               else
285                 {
286                   success = TRUE;
287                   info = (GtkModuleInfo *) g_slist_find_custom (gtk_modules, module,
288                                                                 (GCompareFunc)cmp_module);
289                   if (!info)
290                     {
291                       info = g_new0 (GtkModuleInfo, 1);
292                       
293                       info->names = g_slist_prepend (info->names, g_strdup (name));
294                       info->module = module;
295                       info->ref_count = 1;
296                       info->init_func = modinit_func;
297                       g_module_symbol (module, "gtk_module_display_init",
298                                        (gpointer *) &info->display_init_func);
299                       
300                       gtk_modules = g_slist_prepend (gtk_modules, info);
301                       
302                       /* display_init == NULL indicates a non-multihead aware module.
303                        * For these, we delay the call to init_func until first display is 
304                        * opened, see default_display_notify_cb().
305                        * For multihead aware modules, we call init_func immediately,
306                        * and also call display_init_func on all opened displays.
307                        */
308                       if (default_display_opened || info->display_init_func)
309                         (* info->init_func) (&gtk_argc, &gtk_argv);
310                       
311                       if (info->display_init_func) 
312                         {
313                           GSList *displays, *iter;                
314                           displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
315                           for (iter = displays; iter; iter = iter->next)
316                             {
317                               GdkDisplay *display = iter->data;
318                           (* info->display_init_func) (display);
319                             }
320                           g_slist_free (displays);
321                         }
322                     }
323                   else
324                     {
325                       GTK_NOTE (MODULES, g_print ("Module already loaded, ignoring: %s\n", name));
326                       info->names = g_slist_prepend (info->names, g_strdup (name));
327                       info->ref_count++;
328                       /* remove new reference count on module, we already have one */
329                       g_module_close (module);
330                     }
331                 }
332             }
333         }
334     }
335
336   if (success)
337     {
338       if (!g_slist_find (module_list, info))
339         {
340           module_list = g_slist_prepend (module_list, info);
341         }
342     }
343   else
344     g_message ("Failed to load module \"%s\": %s", name, g_module_error ());
345   
346   return module_list;
347 }
348
349
350 static void
351 gtk_module_info_unref (GtkModuleInfo *info)
352 {
353   GSList *l;
354
355   info->ref_count--;
356
357   if (info->ref_count == 0) 
358     {
359       GTK_NOTE (MODULES, 
360                 g_print ("Unloading module: %s", g_module_name (info->module)));
361
362       gtk_modules = g_slist_remove (gtk_modules, info);
363       g_module_close (info->module);
364       for (l = info->names; l; l = l->next)
365         g_free (l->data);
366       g_slist_free (info->names);
367       g_free (info);
368     }
369 }
370
371 static GSList *
372 load_modules (const char *module_str)
373 {
374   gchar **module_names;
375   GSList *module_list = NULL;
376   gint i;
377
378   GTK_NOTE (MODULES, g_print ("Loading module list: %s", module_str));
379
380   module_names = pango_split_file_list (module_str);
381   for (i = 0; module_names[i]; i++) 
382     module_list = load_module (module_list, module_names[i]);
383
384   module_list = g_slist_reverse (module_list);
385   g_strfreev (module_names);
386
387   return module_list;
388 }
389
390 static void
391 default_display_notify_cb (GdkDisplayManager *display_manager)
392 {
393   GSList *slist;
394
395   /* Initialize non-multihead-aware modules when the
396    * default display is first set to a non-NULL value.
397    */
398
399   if (!gdk_display_get_default () || default_display_opened)
400     return;
401
402   default_display_opened = TRUE;
403
404   for (slist = gtk_modules; slist; slist = slist->next)
405     {
406       if (slist->data)
407         {
408           GtkModuleInfo *info = slist->data;
409
410           if (!info->display_init_func)
411             (* info->init_func) (&gtk_argc, &gtk_argv);
412         }
413     }
414 }
415
416 static void
417 display_closed_cb (GdkDisplay *display,
418                    gboolean    is_error)
419 {
420   GdkScreen *screen;
421   GtkSettings *settings;
422   gint i;
423
424   for (i = 0; i < gdk_display_get_n_screens (display); i++)
425     {
426       screen = gdk_display_get_screen (display, i);
427
428       settings = gtk_settings_get_for_screen (screen);
429
430       g_object_set_data_full (G_OBJECT (settings),
431                               "gtk-modules",
432                               NULL, NULL);
433     }  
434 }
435                    
436
437 static void
438 display_opened_cb (GdkDisplayManager *display_manager,
439                    GdkDisplay        *display)
440 {
441   GSList *slist;
442   GdkScreen *screen;
443   GtkSettings *settings;
444   gint i;
445
446   for (slist = gtk_modules; slist; slist = slist->next)
447     {
448       if (slist->data)
449         {
450           GtkModuleInfo *info = slist->data;
451
452           if (info->display_init_func)
453             (* info->display_init_func) (display);
454         }
455     }
456   
457   for (i = 0; i < gdk_display_get_n_screens (display); i++)
458     {
459       GValue value = { 0, };
460
461       g_value_init (&value, G_TYPE_STRING);
462
463       screen = gdk_display_get_screen (display, i);
464
465       if (gdk_screen_get_setting (screen, "gtk-modules", &value))
466         {
467           settings = gtk_settings_get_for_screen (screen);
468           _gtk_modules_settings_changed (settings, g_value_get_string (&value));
469           g_value_unset (&value);
470         }
471     }
472
473   /* Since closing display doesn't actually release the resources yet,
474    * we have to connect to the ::closed signal.
475    */
476   g_signal_connect (display, "closed", G_CALLBACK (display_closed_cb), NULL);
477 }
478
479 void
480 _gtk_modules_init (gint        *argc, 
481                    gchar     ***argv, 
482                    const gchar *gtk_modules_args)
483 {
484   GdkDisplayManager *display_manager;
485   gint i;
486
487   g_assert (gtk_argv == NULL);
488
489   if (argc && argv) 
490     {
491       /* store argc and argv for later use in mod initialization */
492       gtk_argc = *argc;
493       gtk_argv = g_new (gchar *, *argc + 1);
494       for (i = 0; i < gtk_argc; i++)
495         gtk_argv [i] = g_strdup ((*argv) [i]);
496       gtk_argv [*argc] = NULL;
497     }
498
499   display_manager = gdk_display_manager_get ();
500   g_signal_connect (display_manager, "notify::default-display",
501                     G_CALLBACK (default_display_notify_cb), 
502                     NULL);
503   g_signal_connect (display_manager, "display-opened",
504                     G_CALLBACK (display_opened_cb), 
505                     NULL);
506
507   /* Modules specified in the GTK_MODULES environment variable
508    * or on the command line are always loaded, so we'll just leak 
509    * the refcounts.
510    */
511   g_slist_free (load_modules (gtk_modules_args));
512 }
513
514 static void
515 settings_destroy_notify (gpointer data)
516 {
517   GSList *iter, *modules = data;
518
519   for (iter = modules; iter; iter = iter->next) 
520     {
521       GtkModuleInfo *info = iter->data;
522       gtk_module_info_unref (info);
523     }
524   g_slist_free (modules);
525 }
526
527 void
528 _gtk_modules_settings_changed (GtkSettings *settings, 
529                                const gchar *modules)
530 {
531   GSList *new_modules = NULL;
532
533   /* load/ref before unreffing existing */
534   if (modules && modules[0])
535     new_modules = load_modules (modules);
536
537   g_object_set_data_full (G_OBJECT (settings),
538                           "gtk-modules",
539                           new_modules,
540                           settings_destroy_notify);
541 }