]> Pileus Git - ~andy/gtk/blob - gtk/gtkmodules.c
Updated galician translations
[~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
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 **
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-3.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-3.0", NULL);
75   else
76     default_dir = g_build_filename (GTK_LIBDIR, "gtk-3.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_LOCAL | 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   gpointer modinit_func_ptr;
257   GtkModuleInfo *info = NULL;
258   GModule *module = NULL;
259   GSList *l;
260   gboolean success = FALSE;
261   
262   if (g_module_supported ())
263     {
264       for (l = gtk_modules; l; l = l->next)
265         {
266           info = l->data;
267           if (g_slist_find_custom (info->names, name, 
268                                    (GCompareFunc)strcmp))
269             {
270               info->ref_count++;
271               
272               success = TRUE;
273             }
274         }
275
276       if (!success) 
277         {
278           module = find_module (name);
279
280           if (module)
281             {
282               if (g_module_symbol (module, "gtk_module_init", &modinit_func_ptr))
283                 modinit_func = modinit_func_ptr;
284               else
285                 modinit_func = NULL;
286
287               if (!modinit_func)
288                 g_module_close (module);
289               else
290                 {
291                   GSList *temp;
292
293                   success = TRUE;
294                   info = NULL;
295
296                   temp = g_slist_find_custom (gtk_modules, module,
297                         (GCompareFunc)cmp_module);
298                   if (temp != NULL)
299                         info = temp->data;
300
301                   if (!info)
302                     {
303                       info = g_new0 (GtkModuleInfo, 1);
304                       
305                       info->names = g_slist_prepend (info->names, g_strdup (name));
306                       info->module = module;
307                       info->ref_count = 1;
308                       info->init_func = modinit_func;
309                       g_module_symbol (module, "gtk_module_display_init",
310                                        (gpointer *) &info->display_init_func);
311                       
312                       gtk_modules = g_slist_append (gtk_modules, info);
313                       
314                       /* display_init == NULL indicates a non-multihead aware module.
315                        * For these, we delay the call to init_func until first display is 
316                        * opened, see default_display_notify_cb().
317                        * For multihead aware modules, we call init_func immediately,
318                        * and also call display_init_func on all opened displays.
319                        */
320                       if (default_display_opened || info->display_init_func)
321                         (* info->init_func) (&gtk_argc, &gtk_argv);
322                       
323                       if (info->display_init_func) 
324                         {
325                           GSList *displays, *iter;                
326                           displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
327                           for (iter = displays; iter; iter = iter->next)
328                             {
329                               GdkDisplay *display = iter->data;
330                           (* info->display_init_func) (display);
331                             }
332                           g_slist_free (displays);
333                         }
334                     }
335                   else
336                     {
337                       GTK_NOTE (MODULES, g_print ("Module already loaded, ignoring: %s\n", name));
338                       info->names = g_slist_prepend (info->names, g_strdup (name));
339                       info->ref_count++;
340                       /* remove new reference count on module, we already have one */
341                       g_module_close (module);
342                     }
343                 }
344             }
345         }
346     }
347
348   if (success)
349     {
350       if (!g_slist_find (module_list, info))
351         {
352           module_list = g_slist_prepend (module_list, info);
353         }
354     }
355   else
356     g_message ("Failed to load module \"%s\": %s", name, g_module_error ());
357   
358   return module_list;
359 }
360
361
362 static void
363 gtk_module_info_unref (GtkModuleInfo *info)
364 {
365   GSList *l;
366
367   info->ref_count--;
368
369   if (info->ref_count == 0) 
370     {
371       GTK_NOTE (MODULES, 
372                 g_print ("Unloading module: %s\n", g_module_name (info->module)));
373
374       gtk_modules = g_slist_remove (gtk_modules, info);
375       g_module_close (info->module);
376       for (l = info->names; l; l = l->next)
377         g_free (l->data);
378       g_slist_free (info->names);
379       g_free (info);
380     }
381 }
382
383 static GSList *
384 load_modules (const char *module_str)
385 {
386   gchar **module_names;
387   GSList *module_list = NULL;
388   gint i;
389
390   GTK_NOTE (MODULES, g_print ("Loading module list: %s\n", module_str));
391
392   module_names = pango_split_file_list (module_str);
393   for (i = 0; module_names[i]; i++) 
394     module_list = load_module (module_list, module_names[i]);
395
396   module_list = g_slist_reverse (module_list);
397   g_strfreev (module_names);
398
399   return module_list;
400 }
401
402 static void
403 default_display_notify_cb (GdkDisplayManager *display_manager)
404 {
405   GSList *slist;
406
407   /* Initialize non-multihead-aware modules when the
408    * default display is first set to a non-NULL value.
409    */
410
411   if (!gdk_display_get_default () || default_display_opened)
412     return;
413
414   default_display_opened = TRUE;
415
416   for (slist = gtk_modules; slist; slist = slist->next)
417     {
418       if (slist->data)
419         {
420           GtkModuleInfo *info = slist->data;
421
422           if (!info->display_init_func)
423             (* info->init_func) (&gtk_argc, &gtk_argv);
424         }
425     }
426 }
427
428 static void
429 display_closed_cb (GdkDisplay *display,
430                    gboolean    is_error)
431 {
432   GdkScreen *screen;
433   GtkSettings *settings;
434   gint i;
435
436   for (i = 0; i < gdk_display_get_n_screens (display); i++)
437     {
438       screen = gdk_display_get_screen (display, i);
439
440       settings = gtk_settings_get_for_screen (screen);
441
442       g_object_set_data_full (G_OBJECT (settings),
443                               I_("gtk-modules"),
444                               NULL, NULL);
445     }  
446 }
447                    
448
449 static void
450 display_opened_cb (GdkDisplayManager *display_manager,
451                    GdkDisplay        *display)
452 {
453   GSList *slist;
454   GdkScreen *screen;
455   GtkSettings *settings;
456   gint i;
457
458   for (slist = gtk_modules; slist; slist = slist->next)
459     {
460       if (slist->data)
461         {
462           GtkModuleInfo *info = slist->data;
463
464           if (info->display_init_func)
465             (* info->display_init_func) (display);
466         }
467     }
468   
469   for (i = 0; i < gdk_display_get_n_screens (display); i++)
470     {
471       GValue value = { 0, };
472
473       g_value_init (&value, G_TYPE_STRING);
474
475       screen = gdk_display_get_screen (display, i);
476
477       if (gdk_screen_get_setting (screen, "gtk-modules", &value))
478         {
479           settings = gtk_settings_get_for_screen (screen);
480           _gtk_modules_settings_changed (settings, g_value_get_string (&value));
481           g_value_unset (&value);
482         }
483     }
484
485   /* Since closing display doesn't actually release the resources yet,
486    * we have to connect to the ::closed signal.
487    */
488   g_signal_connect (display, "closed", G_CALLBACK (display_closed_cb), NULL);
489 }
490
491 void
492 _gtk_modules_init (gint        *argc, 
493                    gchar     ***argv, 
494                    const gchar *gtk_modules_args)
495 {
496   GdkDisplayManager *display_manager;
497   gint i;
498
499   g_assert (gtk_argv == NULL);
500
501   if (argc && argv) 
502     {
503       /* store argc and argv for later use in mod initialization */
504       gtk_argc = *argc;
505       gtk_argv = g_new (gchar *, *argc + 1);
506       for (i = 0; i < gtk_argc; i++)
507         gtk_argv [i] = g_strdup ((*argv) [i]);
508       gtk_argv [*argc] = NULL;
509     }
510
511   display_manager = gdk_display_manager_get ();
512   default_display_opened = gdk_display_get_default () != NULL;
513   g_signal_connect (display_manager, "notify::default-display",
514                     G_CALLBACK (default_display_notify_cb), 
515                     NULL);
516   g_signal_connect (display_manager, "display-opened",
517                     G_CALLBACK (display_opened_cb), 
518                     NULL);
519
520   if (gtk_modules_args) {
521     /* Modules specified in the GTK_MODULES environment variable
522      * or on the command line are always loaded, so we'll just leak 
523      * the refcounts.
524      */
525     g_slist_free (load_modules (gtk_modules_args));
526   }
527 }
528
529 static void
530 settings_destroy_notify (gpointer data)
531 {
532   GSList *iter, *modules = data;
533
534   for (iter = modules; iter; iter = iter->next) 
535     {
536       GtkModuleInfo *info = iter->data;
537       gtk_module_info_unref (info);
538     }
539   g_slist_free (modules);
540 }
541
542 void
543 _gtk_modules_settings_changed (GtkSettings *settings, 
544                                const gchar *modules)
545 {
546   GSList *new_modules = NULL;
547
548   GTK_NOTE (MODULES, g_print ("gtk-modules setting changed to: %s\n", modules));
549
550   /* load/ref before unreffing existing */
551   if (modules && modules[0])
552     new_modules = load_modules (modules);
553
554   g_object_set_data_full (G_OBJECT (settings),
555                           I_("gtk-modules"),
556                           new_modules,
557                           settings_destroy_notify);
558 }