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