1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * libglade - a library for building interfaces from XML files at runtime
3  * Copyright (C) 1998-2002  James Henstridge <james@daa.com.au>
4  *
5  * glade-init.c: initialisation functions for libglade
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA  02111-1307, USA.
21  */
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25 
26 #include <string.h>
27 #include <glib.h>
28 #include <gmodule.h>
29 
30 #include <pango/pango-utils.h>
31 
32 #include "glade-init.h"
33 #include "glade-build.h"
34 #include "glade-private.h"
35 
36 #ifdef DEBUG
37 guint _glade_debug_flags = 0;
38 #endif
39 
40 #ifdef G_OS_WIN32
41 
42 #include <windows.h>
43 
44 static HMODULE hmodule;
45 G_LOCK_DEFINE_STATIC (mutex);
46 
47 /* DllMain used to tuck away the DLL's HMODULE */
48 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)49 DllMain (HINSTANCE hinstDLL,
50 	 DWORD     fdwReason,
51 	 LPVOID    lpvReserved)
52 {
53 	switch (fdwReason) {
54 	case DLL_PROCESS_ATTACH:
55 		hmodule = hinstDLL;
56 		break;
57 	}
58 	return TRUE;
59 }
60 
61 static char *
replace_prefix(const char * runtime_prefix,const char * configure_time_path)62 replace_prefix (const char *runtime_prefix,
63 		const char *configure_time_path)
64 {
65 	if (runtime_prefix &&
66 	    strncmp (configure_time_path, GLADE_PREFIX "/", strlen (GLADE_PREFIX) + 1) == 0) {
67 		return g_strconcat (runtime_prefix,
68 				    configure_time_path + strlen (GLADE_PREFIX),
69 				    NULL);
70 	} else
71 		return g_strdup (configure_time_path);
72 }
73 
74 static const char *
get_libdir(void)75 get_libdir (void)
76 {
77     static const char *libdir = NULL;
78     char *prefix = NULL;
79 
80     G_LOCK (mutex);
81     if (libdir != NULL) {
82 	G_UNLOCK (mutex);
83 	return libdir;
84     }
85 
86 
87     if (GetVersion () < 0x80000000) {
88 	wchar_t wcbfr[1000];
89 
90 	if (GetModuleFileNameW (hmodule, wcbfr,
91 				G_N_ELEMENTS (wcbfr))) {
92 	    prefix = g_utf16_to_utf8 (wcbfr, -1, NULL, NULL, NULL);
93 	}
94     } else {
95 	char cpbfr[1000];
96 	if (GetModuleFileNameA (hmodule, cpbfr, G_N_ELEMENTS (cpbfr)))
97 	    prefix = g_locale_to_utf8 (cpbfr, -1, NULL, NULL, NULL);
98     }
99 
100     if (prefix != NULL) {
101 	char *p = strrchr (prefix, '\\');
102 	if (p != NULL)
103 	    *p = '\0';
104 
105 	p = strrchr (prefix, '\\');
106 	if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0))
107 	    *p = '\0';
108     }
109 
110     libdir = replace_prefix (prefix, GLADE_LIBDIR);
111 
112     G_UNLOCK (mutex);
113 
114     return libdir;
115 }
116 
117 #undef GLADE_LIBDIR
118 #define GLADE_LIBDIR get_libdir ()
119 
120 #endif
121 
122 void _glade_init_gtk_widgets (void);
123 
124 /**
125  * glade_init:
126  *
127  * It used to be necessary to call glade_init() before creating
128  * GladeXML objects.  This is now no longer the case, as libglade will
129  * be initialised on demand now.  Calling glade_init() manually will
130  * not cause any problems though.
131  */
132 void
glade_init(void)133 glade_init(void)
134 {
135     static gboolean initialised = FALSE;
136 #ifdef DEBUG
137     const gchar *env_string;
138 #endif
139 
140     if (initialised) return;
141     initialised = TRUE;
142     _glade_init_gtk_widgets();
143 
144 #ifdef DEBUG
145     env_string = g_getenv("LIBGLADE_DEBUG");
146     if (env_string != NULL) {
147 	const GDebugKey libglade_debug_keys[] = {
148 		{ "parser", GLADE_DEBUG_PARSER },
149 		{ "build",  GLADE_DEBUG_BUILD },
150 	};
151 
152 	_glade_debug_flags = g_parse_debug_string (env_string,
153 						   libglade_debug_keys,
154 						   G_N_ELEMENTS (libglade_debug_keys));
155 	env_string = NULL;
156     }
157 #endif
158 
159 }
160 
161 gchar *
glade_module_check_version(gint version)162 glade_module_check_version(gint version)
163 {
164   if (version != GLADE_MODULE_API_VERSION)
165     return "Wrong plugin API version";
166   else
167     return NULL;
168 }
169 
170 static GPtrArray *loaded_packages = NULL;
171 
172 static gchar **
get_module_path(void)173 get_module_path (void)
174 {
175     const gchar *module_path_env = g_getenv ("LIBGLADE_MODULE_PATH");
176     const gchar *exe_prefix = g_getenv("LIBGLADE_EXE_PREFIX");
177     gchar **result;
178     gchar *module_path;
179     gchar *default_dir;
180 
181     if (exe_prefix)
182 	default_dir = g_build_filename (exe_prefix, "lib", "libglade", "2.0", NULL);
183     else
184 	default_dir = g_build_filename (GLADE_LIBDIR, "libglade", "2.0", NULL);
185 
186     module_path = g_strconcat (module_path_env ? module_path_env : "",
187 			       module_path_env ? G_SEARCHPATH_SEPARATOR_S : "",
188 			       default_dir, NULL);
189 
190     result = pango_split_file_list (module_path);
191 
192     g_free (default_dir);
193     g_free (module_path);
194 
195     return result;
196 }
197 
198 static GModule *
find_module(gchar ** module_path,const gchar * name)199 find_module (gchar      **module_path,
200 	     const gchar *name)
201 {
202     GModule *module;
203     gchar *module_name;
204     gint i;
205 
206     if (g_path_is_absolute (name))
207 	return g_module_open (name, G_MODULE_BIND_LAZY);
208 
209     for (i = 0; module_path[i]; i++) {
210 	module_name = g_module_build_path (module_path[i], name);
211 
212 	if (g_file_test (module_name, G_FILE_TEST_EXISTS)) {
213 	    module = g_module_open (module_name, G_MODULE_BIND_LAZY);
214 	    g_free (module_name);
215 	    return module;
216 	}
217 
218 	g_free (module_name);
219     }
220 
221     /* As last resort, try loading without an absolute path (using system
222      * library path)
223      */
224     module_name = g_module_build_path (NULL, name);
225     module = g_module_open (module_name, G_MODULE_BIND_LAZY);
226     g_free(module_name);
227 
228     return module;
229 }
230 
231 /**
232  * glade_require:
233  * @library: the required library
234  *
235  * Ensure that a required library is available.  If it is not already
236  * available, libglade will attempt to dynamically load a module that
237  * contains the handlers for that library.
238  */
239 
240 void
glade_require(const gchar * library)241 glade_require(const gchar *library)
242 {
243     gboolean already_loaded = FALSE;
244     GModule *module;
245     void (* init_func)(void);
246     static char **module_path = NULL;
247 
248     /* a call to glade_init here to make sure libglade is initialised */
249     glade_init();
250 
251     if (loaded_packages) {
252 	gint i;
253 
254 	for (i = 0; i < loaded_packages->len; i++)
255 	    if (!strcmp(library, g_ptr_array_index(loaded_packages, i))) {
256 		already_loaded = TRUE;
257 		break;
258 	    }
259     }
260 
261     if (already_loaded)
262 	return;
263 
264     if (!module_path)
265 	module_path = get_module_path ();
266 
267     module = find_module (module_path, library);
268 
269     if (!module) {
270 	g_warning("Could not load support for `%s': %s", library,
271 		  g_module_error());
272 	return;
273     }
274 
275     if (!g_module_symbol(module, "glade_module_register_widgets",
276 			 (gpointer)&init_func)) {
277 	g_warning("could not find `%s' init function: %s", library,
278 		  g_module_error());
279 	g_module_close(module);
280 	return;
281     }
282 
283     init_func();
284     g_module_make_resident(module);
285 }
286 
287 /**
288  * glade_provide:
289  * @library: the provided library
290  *
291  * This function should be called by a module to assert that it
292  * provides wrappers for a particular library.  This should be called
293  * by the register_widgets() function of a libglade module so that it
294  * isn't loaded twice, for instance.
295  */
296 
297 void
glade_provide(const gchar * library)298 glade_provide(const gchar *library)
299 {
300     gboolean already_loaded = FALSE;
301     gint i;
302 
303     if (!loaded_packages)
304 	loaded_packages = g_ptr_array_new();
305 
306     for (i = 0; i < loaded_packages->len; i++)
307 	if (!strcmp(library, g_ptr_array_index(loaded_packages, i))) {
308 	    already_loaded = TRUE;
309 	    break;
310 	}
311 
312     if (!already_loaded)
313 	g_ptr_array_add(loaded_packages, g_strdup(library));
314 }
315 
316 /**
317  * GLADE_MODULE_CHECK_INIT:
318  *
319  * This macro will insert a suitable version check function into a
320  * libglade loadable module.
321  */
322