1 /*
2 * caja-module.h - Interface to caja 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, write to the Free
18 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * Author: Dave Camp <dave@ximian.com>
21 *
22 */
23
24 #include <config.h>
25 #include <gmodule.h>
26
27 #include <eel/eel-gtk-macros.h>
28 #include <eel/eel-debug.h>
29
30 #include "caja-module.h"
31 #include "caja-extensions.h"
32
33 #define CAJA_TYPE_MODULE (caja_module_get_type ())
34 #define CAJA_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CAJA_TYPE_MODULE, CajaModule))
35
36 typedef struct _CajaModule CajaModule;
37 typedef struct _CajaModuleClass CajaModuleClass;
38
39 struct _CajaModule
40 {
41 GTypeModule parent;
42
43 GModule *library;
44
45 char *path;
46
47 void (*initialize) (GTypeModule *module);
48 void (*shutdown) (void);
49
50 void (*list_types) (const GType **types,
51 int *num_types);
52 void (*list_pyfiles) (GList **pyfiles);
53
54 };
55
56 struct _CajaModuleClass
57 {
58 GTypeModuleClass parent;
59 };
60
61 static GList *module_objects = NULL;
62
63 static GType caja_module_get_type (void);
64
65 G_DEFINE_TYPE (CajaModule, caja_module, G_TYPE_TYPE_MODULE);
66 #define parent_class caja_module_parent_class
67
68 static gboolean
caja_module_load(GTypeModule * gmodule)69 caja_module_load (GTypeModule *gmodule)
70 {
71 CajaModule *module;
72
73 module = CAJA_MODULE (gmodule);
74
75 module->library = g_module_open (module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
76
77 if (!module->library)
78 {
79 g_warning ("%s", g_module_error ());
80 return FALSE;
81 }
82
83 if (!g_module_symbol (module->library,
84 "caja_module_initialize",
85 (gpointer *)&module->initialize) ||
86 !g_module_symbol (module->library,
87 "caja_module_shutdown",
88 (gpointer *)&module->shutdown) ||
89 !g_module_symbol (module->library,
90 "caja_module_list_types",
91 (gpointer *)&module->list_types))
92 {
93
94 g_warning ("%s", g_module_error ());
95 g_module_close (module->library);
96
97 return FALSE;
98 }
99
100 g_module_symbol (module->library,
101 "caja_module_list_pyfiles",
102 (gpointer *)&module->list_pyfiles);
103
104 module->initialize (gmodule);
105
106 return TRUE;
107 }
108
109 static void
caja_module_unload(GTypeModule * gmodule)110 caja_module_unload (GTypeModule *gmodule)
111 {
112 CajaModule *module;
113
114 module = CAJA_MODULE (gmodule);
115
116 module->shutdown ();
117
118 g_module_close (module->library);
119
120 module->initialize = NULL;
121 module->shutdown = NULL;
122 module->list_types = NULL;
123 }
124
125 static void
caja_module_finalize(GObject * object)126 caja_module_finalize (GObject *object)
127 {
128 CajaModule *module;
129
130 module = CAJA_MODULE (object);
131
132 g_free (module->path);
133
134 EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
135 }
136
137 static void
caja_module_init(CajaModule * module)138 caja_module_init (CajaModule *module)
139 {
140 }
141
142 static void
caja_module_class_init(CajaModuleClass * class)143 caja_module_class_init (CajaModuleClass *class)
144 {
145 G_OBJECT_CLASS (class)->finalize = caja_module_finalize;
146 G_TYPE_MODULE_CLASS (class)->load = caja_module_load;
147 G_TYPE_MODULE_CLASS (class)->unload = caja_module_unload;
148 }
149
150 static void
module_object_weak_notify(gpointer user_data,GObject * object)151 module_object_weak_notify (gpointer user_data, GObject *object)
152 {
153 module_objects = g_list_remove (module_objects, object);
154 }
155
156 static void
add_module_objects(CajaModule * module)157 add_module_objects (CajaModule *module)
158 {
159 GObject *object = NULL;
160 GList *pyfiles = NULL;
161 gchar *filename = NULL;
162 const GType *types = NULL;
163 int num_types = 0;
164 int i;
165
166 module->list_types (&types, &num_types);
167 filename = g_path_get_basename (module->path);
168
169 /* fetch extensions details loaded through python-caja module */
170 if (module->list_pyfiles)
171 {
172 module->list_pyfiles(&pyfiles);
173 }
174
175 for (i = 0; i < num_types; i++)
176 {
177 if (types[i] == 0) /* Work around broken extensions */
178 {
179 break;
180 }
181
182 if (module->list_pyfiles)
183 {
184 filename = g_strconcat(g_list_nth_data(pyfiles, i), ".py", NULL);
185 }
186
187 object = caja_module_add_type (types[i]);
188 caja_extension_register (filename, object);
189 }
190 }
191
192 static CajaModule *
caja_module_load_file(const char * filename)193 caja_module_load_file (const char *filename)
194 {
195 CajaModule *module;
196
197 module = g_object_new (CAJA_TYPE_MODULE, NULL);
198 module->path = g_strdup (filename);
199
200 if (g_type_module_use (G_TYPE_MODULE (module)))
201 {
202 add_module_objects (module);
203 g_type_module_unuse (G_TYPE_MODULE (module));
204 return module;
205 }
206 else
207 {
208 g_object_unref (module);
209 return NULL;
210 }
211 }
212
213 static void
load_module_dir(const char * dirname)214 load_module_dir (const char *dirname)
215 {
216 GDir *dir;
217
218 dir = g_dir_open (dirname, 0, NULL);
219
220 if (dir)
221 {
222 const char *name;
223
224 while ((name = g_dir_read_name (dir)))
225 {
226 if (g_str_has_suffix (name, "." G_MODULE_SUFFIX))
227 {
228 char *filename;
229
230 filename = g_build_filename (dirname,
231 name,
232 NULL);
233 caja_module_load_file (filename);
234 }
235 }
236 g_dir_close (dir);
237 }
238 }
239
240 static void
free_module_objects(void)241 free_module_objects (void)
242 {
243 GList *l, *next;
244
245 for (l = module_objects; l != NULL; l = next)
246 {
247 next = l->next;
248 g_object_unref (l->data);
249 }
250
251 g_list_free (module_objects);
252 }
253
254 void
caja_module_setup(void)255 caja_module_setup (void)
256 {
257 static gboolean initialized = FALSE;
258
259 if (!initialized)
260 {
261 const gchar *caja_extension_dirs = g_getenv ("CAJA_EXTENSION_DIRS");
262
263 initialized = TRUE;
264
265 if (caja_extension_dirs)
266 {
267 gchar **dir_vector = g_strsplit (caja_extension_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
268
269 for (gchar **dir = dir_vector; *dir != NULL; ++ dir)
270 load_module_dir (*dir);
271
272 g_strfreev(dir_vector);
273 }
274
275 load_module_dir (CAJA_EXTENSIONDIR);
276
277 eel_debug_call_at_shutdown (free_module_objects);
278 }
279 }
280
281 GList *
caja_module_get_extensions_for_type(GType type)282 caja_module_get_extensions_for_type (GType type)
283 {
284 GList *l;
285 GList *ret = NULL;
286
287 for (l = module_objects; l != NULL; l = l->next)
288 {
289 if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (l->data),
290 type))
291 {
292 g_object_ref (l->data);
293 ret = g_list_prepend (ret, l->data);
294 }
295 }
296
297 return ret;
298 }
299
300 void
caja_module_extension_list_free(GList * extensions)301 caja_module_extension_list_free (GList *extensions)
302 {
303 GList *l, *next;
304
305 for (l = extensions; l != NULL; l = next)
306 {
307 next = l->next;
308 g_object_unref (l->data);
309 }
310 g_list_free (extensions);
311 }
312
313 GObject *
caja_module_add_type(GType type)314 caja_module_add_type (GType type)
315 {
316 GObject *object;
317
318 object = g_object_new (type, NULL);
319 g_object_weak_ref (object,
320 (GWeakNotify)module_object_weak_notify,
321 NULL);
322
323 module_objects = g_list_prepend (module_objects, object);
324 return object;
325 }
326