1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  *  nemo-module.h - Interface to nemo extensions
4  *
5  *  Copyright (C) 2003 Novell, Inc.
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 Free
19  *  Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA.
20  *
21  *  Author: Dave Camp <dave@ximian.com>
22  *
23  */
24 
25 #include <config.h>
26 #include "nemo-module.h"
27 #include <libnemo-private/nemo-global-preferences.h>
28 
29 #include <eel/eel-debug.h>
30 
31 static GList *module_objects = NULL;
32 
33 G_DEFINE_TYPE (NemoModule, nemo_module, G_TYPE_TYPE_MODULE);
34 
35 static gboolean
nemo_module_load(GTypeModule * gmodule)36 nemo_module_load (GTypeModule *gmodule)
37 {
38 	NemoModule *module;
39 
40 	module = NEMO_MODULE (gmodule);
41 
42 	module->library = g_module_open (module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
43 
44 	if (!module->library) {
45 		g_warning ("%s", g_module_error ());
46 		return FALSE;
47 	}
48 
49 	if (!g_module_symbol (module->library,
50 			      "nemo_module_initialize",
51 			      (gpointer *)&module->initialize) ||
52 	    !g_module_symbol (module->library,
53 			      "nemo_module_shutdown",
54 			      (gpointer *)&module->shutdown) ||
55 	    !g_module_symbol (module->library,
56 			      "nemo_module_list_types",
57 			      (gpointer *)&module->list_types)) {
58 
59 		g_warning ("%s", g_module_error ());
60 		g_module_close (module->library);
61 
62 		return FALSE;
63 	}
64 
65 	module->initialize (gmodule);
66 
67 	return TRUE;
68 }
69 
70 static void
nemo_module_unload(GTypeModule * gmodule)71 nemo_module_unload (GTypeModule *gmodule)
72 {
73 	NemoModule *module;
74 
75 	module = NEMO_MODULE (gmodule);
76 
77 	module->shutdown ();
78 
79 	g_module_close (module->library);
80 
81 	module->initialize = NULL;
82 	module->shutdown = NULL;
83 	module->list_types = NULL;
84 }
85 
86 static void
nemo_module_finalize(GObject * object)87 nemo_module_finalize (GObject *object)
88 {
89 	NemoModule *module;
90 
91 	module = NEMO_MODULE (object);
92 
93 	g_free (module->path);
94 
95 	G_OBJECT_CLASS (nemo_module_parent_class)->finalize (object);
96 }
97 
98 static void
nemo_module_init(NemoModule * module)99 nemo_module_init (NemoModule *module)
100 {
101 }
102 
103 static void
nemo_module_class_init(NemoModuleClass * class)104 nemo_module_class_init (NemoModuleClass *class)
105 {
106 	G_OBJECT_CLASS (class)->finalize = nemo_module_finalize;
107 	G_TYPE_MODULE_CLASS (class)->load = nemo_module_load;
108 	G_TYPE_MODULE_CLASS (class)->unload = nemo_module_unload;
109 }
110 
111 static void
module_object_weak_notify(gpointer user_data,GObject * object)112 module_object_weak_notify (gpointer user_data, GObject *object)
113 {
114 	module_objects = g_list_remove (module_objects, object);
115 }
116 
117 static gboolean
module_is_selected(GType type)118 module_is_selected (GType type)
119 {
120     gchar **disabled_list = g_settings_get_strv (nemo_plugin_preferences, NEMO_PLUGIN_PREFERENCES_DISABLED_EXTENSIONS);
121 
122     gboolean ret = TRUE;
123     guint i = 0;
124 
125     for (i = 0; i < g_strv_length (disabled_list); i++) {
126         if (g_strcmp0 (disabled_list[i], g_type_name (type)) == 0)
127             ret = FALSE;
128     }
129 
130     g_strfreev (disabled_list);
131     return ret;
132 }
133 
134 static void
add_module_objects(NemoModule * module)135 add_module_objects (NemoModule *module)
136 {
137 	const GType *types;
138 	int num_types;
139 	int i;
140 
141 	module->list_types (&types, &num_types);
142 
143 	for (i = 0; i < num_types; i++) {
144 		if (types[i] == 0) { /* Work around broken extensions */
145 			break;
146 		}
147         if (module_is_selected (types[i])) {
148             nemo_module_add_type (types[i]);
149         }
150     }
151 }
152 
153 static void
nemo_module_load_file(const char * filename)154 nemo_module_load_file (const char *filename)
155 {
156 	NemoModule *module = NULL;
157 
158     module = g_object_new (NEMO_TYPE_MODULE, NULL);
159     module->path = g_strdup (filename);
160 
161     if (g_type_module_use (G_TYPE_MODULE (module))) {
162         add_module_objects (module);
163         g_type_module_unuse (G_TYPE_MODULE (module));
164     } else {
165         g_object_unref (module);
166     }
167 }
168 
169 static void
load_module_dir(const char * dirname)170 load_module_dir (const char *dirname)
171 {
172 	GDir *dir;
173 
174 	dir = g_dir_open (dirname, 0, NULL);
175 
176 	if (dir) {
177 		const char *name;
178 
179 		while ((name = g_dir_read_name (dir))) {
180 			if (g_str_has_suffix (name, "." G_MODULE_SUFFIX)) {
181 				char *filename;
182 
183 				filename = g_build_filename (dirname,
184 							     name,
185 							     NULL);
186                 nemo_module_load_file (filename);
187 				g_free (filename);
188 			}
189 		}
190 
191 		g_dir_close (dir);
192 	}
193 }
194 
195 static void
free_module_objects(void)196 free_module_objects (void)
197 {
198 	GList *l, *next;
199 
200 	for (l = module_objects; l != NULL; l = next) {
201 		next = l->next;
202 		g_object_unref (l->data);
203 	}
204 
205 	g_list_free (module_objects);
206 }
207 
208 void
nemo_module_setup(void)209 nemo_module_setup (void)
210 {
211 	static gboolean initialized = FALSE;
212 
213 	if (!initialized) {
214 		initialized = TRUE;
215 
216 		load_module_dir (NEMO_EXTENSIONDIR);
217 
218 		eel_debug_call_at_shutdown (free_module_objects);
219 	}
220 }
221 
222 GList *
nemo_module_get_extensions_for_type(GType type)223 nemo_module_get_extensions_for_type (GType type)
224 {
225 	GList *l;
226 	GList *ret = NULL;
227 
228 	for (l = module_objects; l != NULL; l = l->next) {
229 		if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (l->data),
230 						type)) {
231 			g_object_ref (l->data);
232 			ret = g_list_prepend (ret, l->data);
233 		}
234 	}
235 
236 	return ret;
237 }
238 
239 void
nemo_module_extension_list_free(GList * extensions)240 nemo_module_extension_list_free (GList *extensions)
241 {
242 	GList *l, *next;
243 
244 	for (l = extensions; l != NULL; l = next) {
245 		next = l->next;
246 		g_object_unref (l->data);
247 	}
248 	g_list_free (extensions);
249 }
250 
251 void
nemo_module_add_type(GType type)252 nemo_module_add_type (GType type)
253 {
254 	GObject *object;
255 
256 	object = g_object_new (type, NULL);
257 	g_object_weak_ref (object,
258 			   (GWeakNotify)module_object_weak_notify,
259 			   NULL);
260 
261 	module_objects = g_list_prepend (module_objects, object);
262 }
263