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