1 /*
2 * nautilus-module.h - Interface to nautilus extensions
3 *
4 * Copyright (C) 2003 Novell, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Dave Camp <dave@ximian.com>
20 *
21 */
22
23 #include <config.h>
24 #include "nautilus-module.h"
25
26 #include <eel/eel-debug.h>
27 #include <gmodule.h>
28
29 #define NAUTILUS_TYPE_MODULE (nautilus_module_get_type ())
30 #define NAUTILUS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_MODULE, NautilusModule))
31 #define NAUTILUS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_MODULE, NautilusModule))
32 #define NAUTILUS_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_MODULE))
33 #define NAUTILUS_IS_MODULE_CLASS(klass) (G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_MODULE))
34
35 typedef struct _NautilusModule NautilusModule;
36 typedef struct _NautilusModuleClass NautilusModuleClass;
37
38 struct _NautilusModule
39 {
40 GTypeModule parent;
41
42 GModule *library;
43
44 char *path;
45
46 void (*initialize) (GTypeModule *module);
47 void (*shutdown) (void);
48
49 void (*list_types) (const GType **types,
50 int *num_types);
51 };
52
53 struct _NautilusModuleClass
54 {
55 GTypeModuleClass parent;
56 };
57
58 static GList *module_objects = NULL;
59
60 static GType nautilus_module_get_type (void);
61
62 G_DEFINE_TYPE (NautilusModule, nautilus_module, G_TYPE_TYPE_MODULE);
63
64 static gboolean
module_pulls_in_orbit(GModule * module)65 module_pulls_in_orbit (GModule *module)
66 {
67 gpointer symbol;
68 gboolean res;
69
70 res = g_module_symbol (module, "ORBit_realloc_tcval", &symbol);
71
72 return res;
73 }
74
75 static gboolean
nautilus_module_load(GTypeModule * gmodule)76 nautilus_module_load (GTypeModule *gmodule)
77 {
78 NautilusModule *module;
79
80 module = NAUTILUS_MODULE (gmodule);
81
82 module->library = g_module_open (module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
83
84 if (!module->library)
85 {
86 g_warning ("%s", g_module_error ());
87 return FALSE;
88 }
89
90 /* ORBit installs atexit() handlers, which would get unloaded together
91 * with the module now that the main process doesn't depend on GConf anymore,
92 * causing nautilus to sefgault at exit.
93 * If we detect that an extension would pull in ORBit, we make the
94 * module resident to prevent that.
95 */
96 if (module_pulls_in_orbit (module->library))
97 {
98 g_module_make_resident (module->library);
99 }
100
101 if (!g_module_symbol (module->library,
102 "nautilus_module_initialize",
103 (gpointer *) &module->initialize) ||
104 !g_module_symbol (module->library,
105 "nautilus_module_shutdown",
106 (gpointer *) &module->shutdown) ||
107 !g_module_symbol (module->library,
108 "nautilus_module_list_types",
109 (gpointer *) &module->list_types))
110 {
111 g_warning ("%s", g_module_error ());
112 g_module_close (module->library);
113
114 return FALSE;
115 }
116
117 module->initialize (gmodule);
118
119 return TRUE;
120 }
121
122 static void
nautilus_module_unload(GTypeModule * gmodule)123 nautilus_module_unload (GTypeModule *gmodule)
124 {
125 NautilusModule *module;
126
127 module = NAUTILUS_MODULE (gmodule);
128
129 module->shutdown ();
130
131 g_module_close (module->library);
132
133 module->initialize = NULL;
134 module->shutdown = NULL;
135 module->list_types = NULL;
136 }
137
138 static void
nautilus_module_finalize(GObject * object)139 nautilus_module_finalize (GObject *object)
140 {
141 NautilusModule *module;
142
143 module = NAUTILUS_MODULE (object);
144
145 g_free (module->path);
146
147 G_OBJECT_CLASS (nautilus_module_parent_class)->finalize (object);
148 }
149
150 static void
nautilus_module_init(NautilusModule * module)151 nautilus_module_init (NautilusModule *module)
152 {
153 }
154
155 static void
nautilus_module_class_init(NautilusModuleClass * class)156 nautilus_module_class_init (NautilusModuleClass *class)
157 {
158 G_OBJECT_CLASS (class)->finalize = nautilus_module_finalize;
159 G_TYPE_MODULE_CLASS (class)->load = nautilus_module_load;
160 G_TYPE_MODULE_CLASS (class)->unload = nautilus_module_unload;
161 }
162
163 static void
module_object_weak_notify(gpointer user_data,GObject * object)164 module_object_weak_notify (gpointer user_data,
165 GObject *object)
166 {
167 module_objects = g_list_remove (module_objects, object);
168 }
169
170 static void
add_module_objects(NautilusModule * module)171 add_module_objects (NautilusModule *module)
172 {
173 const GType *types;
174 int num_types;
175 int i;
176
177 module->list_types (&types, &num_types);
178
179 for (i = 0; i < num_types; i++)
180 {
181 if (types[i] == 0) /* Work around broken extensions */
182 {
183 break;
184 }
185 nautilus_module_add_type (types[i]);
186 }
187 }
188
189 static NautilusModule *
nautilus_module_load_file(const char * filename)190 nautilus_module_load_file (const char *filename)
191 {
192 NautilusModule *module;
193
194 module = g_object_new (NAUTILUS_TYPE_MODULE, NULL);
195 module->path = g_strdup (filename);
196
197 if (g_type_module_use (G_TYPE_MODULE (module)))
198 {
199 add_module_objects (module);
200 g_type_module_unuse (G_TYPE_MODULE (module));
201 return module;
202 }
203 else
204 {
205 g_object_unref (module);
206 return NULL;
207 }
208 }
209
210 static void
load_module_dir(const char * dirname)211 load_module_dir (const char *dirname)
212 {
213 GDir *dir;
214
215 dir = g_dir_open (dirname, 0, NULL);
216
217 if (dir)
218 {
219 const char *name;
220
221 while ((name = g_dir_read_name (dir)))
222 {
223 if (g_str_has_suffix (name, "." G_MODULE_SUFFIX))
224 {
225 char *filename;
226
227 filename = g_build_filename (dirname,
228 name,
229 NULL);
230 nautilus_module_load_file (filename);
231 g_free (filename);
232 }
233 }
234
235 g_dir_close (dir);
236 }
237 }
238
239 static void
free_module_objects(void)240 free_module_objects (void)
241 {
242 GList *l, *next;
243
244 for (l = module_objects; l != NULL; l = next)
245 {
246 next = l->next;
247 g_object_unref (l->data);
248 }
249
250 g_list_free (module_objects);
251 }
252
253 void
nautilus_module_setup(void)254 nautilus_module_setup (void)
255 {
256 static gboolean initialized = FALSE;
257
258 if (!initialized)
259 {
260 initialized = TRUE;
261
262 load_module_dir (NAUTILUS_EXTENSIONDIR);
263
264 eel_debug_call_at_shutdown (free_module_objects);
265 }
266 }
267
268 GList *
nautilus_module_get_extensions_for_type(GType type)269 nautilus_module_get_extensions_for_type (GType type)
270 {
271 GList *l;
272 GList *ret = NULL;
273
274 for (l = module_objects; l != NULL; l = l->next)
275 {
276 if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (l->data),
277 type))
278 {
279 g_object_ref (l->data);
280 ret = g_list_prepend (ret, l->data);
281 }
282 }
283
284 return ret;
285 }
286
287 void
nautilus_module_extension_list_free(GList * extensions)288 nautilus_module_extension_list_free (GList *extensions)
289 {
290 GList *l, *next;
291
292 for (l = extensions; l != NULL; l = next)
293 {
294 next = l->next;
295 g_object_unref (l->data);
296 }
297 g_list_free (extensions);
298 }
299
300 void
nautilus_module_add_type(GType type)301 nautilus_module_add_type (GType type)
302 {
303 GObject *object;
304
305 object = g_object_new (type, NULL);
306 g_object_weak_ref (object,
307 (GWeakNotify) module_object_weak_notify,
308 NULL);
309
310 module_objects = g_list_prepend (module_objects, object);
311 }
312