1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 anjuta-c-plugin-factory.c
4 Copyright (C) 2007 Sebastien Granjoux <seb.sfo@free.fr>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program 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
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * SECTION:anjuta-c-plugin-factory
23 * @title: AnjutaCPluginFactory
24 * @short_description: Anjuta C plugin factory
25 * @see_also: #AnjutaCModule, #AnjutaPluginManager
26 * @stability: Unstable
27 * @include: libanjuta/anjuta-c-plugin-factory.h
28 *
29 * #AnjutaCPluginFactory implements the #IAnjutaPluginFactory interface. This
30 * interface is used to create new plugin objects in Anjuta.
31 *
32 * This plugin factory creates new plugin objects which have a source code
33 * written in C. This factory is always available in Anjuta. Other plugin
34 * factories can be implemented as Anjuta plugins.
35 *
36 * This plugin factory uses the GLib dynamic type support implemented in
37 * #AnjutaCModule object to allow loading and unloading of plugins code. But
38 * if the plugins itself can be unloaded, the #AnjutaCModule object must stay.
39 * If the plugin is needed later, it must be registed with the same
40 * module object. The factory take care of this and of creating the plugin
41 * object itself.
42 */
43
44 #include "config.h"
45
46 #include "anjuta-c-plugin-factory.h"
47
48 #include "anjuta-c-module.h"
49
50 #include <libanjuta/interfaces/ianjuta-plugin-factory.h>
51
52 #include <glib.h>
53
54 #include <string.h>
55
56 /* Types
57 *---------------------------------------------------------------------------*/
58
59 struct _AnjutaCPluginFactoryClass
60 {
61 GObjectClass parent;
62 };
63
64 struct _AnjutaCPluginFactory
65 {
66 GObject parent;
67
68 GHashTable* loaded_plugins;
69 };
70
71 static void ianjuta_c_plugin_factory_iface_init (IAnjutaPluginFactoryIface *iface);
G_DEFINE_TYPE_WITH_CODE(AnjutaCPluginFactory,anjuta_c_plugin_factory,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (IANJUTA_TYPE_PLUGIN_FACTORY,ianjuta_c_plugin_factory_iface_init))72 G_DEFINE_TYPE_WITH_CODE (AnjutaCPluginFactory, anjuta_c_plugin_factory, G_TYPE_OBJECT, \
73 G_IMPLEMENT_INTERFACE (IANJUTA_TYPE_PLUGIN_FACTORY, ianjuta_c_plugin_factory_iface_init))
74
75 /* Private functions
76 *---------------------------------------------------------------------------*/
77
78 static AnjutaPlugin*
79 anjuta_c_plugin_factory_create_plugin (AnjutaCPluginFactory *factory,
80 AnjutaPluginHandle *handle,
81 AnjutaShell *shell,
82 GError **error)
83 {
84 const gchar *path;
85 GHashTable *plugin_in_path;
86 gchar **pieces;
87 AnjutaCModule *module;
88 GType type;
89 AnjutaPlugin *plugin;
90
91 g_return_val_if_fail (handle != NULL, NULL);
92 g_return_val_if_fail (shell != NULL, NULL);
93
94 path = anjuta_plugin_handle_get_path (handle);
95 plugin_in_path = g_hash_table_lookup (factory->loaded_plugins, path);
96 if (plugin_in_path == NULL)
97 {
98 /* No loaded plugin with this path, create sub hash */
99 plugin_in_path = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
100 g_hash_table_insert (plugin_in_path, g_strdup (path), plugin_in_path);
101 }
102
103 pieces = g_strsplit (anjuta_plugin_handle_get_id (handle), ":", -1);
104 if ((pieces == NULL) || (pieces[0] == NULL))
105 {
106 g_set_error (error, IANJUTA_PLUGIN_FACTORY_ERROR,
107 IANJUTA_PLUGIN_FACTORY_MISSING_LOCATION,
108 _("Missing location of plugin %s"), anjuta_plugin_handle_get_name (handle));
109 return NULL;
110 }
111 module = g_hash_table_lookup (plugin_in_path, pieces[0]);
112 if (module == NULL)
113 {
114 /* Plugin is not loaded */
115 module = anjuta_c_module_new (path, pieces[0]);
116 g_return_val_if_fail (module != NULL, NULL);
117
118 /* Load module */
119 g_type_module_use (G_TYPE_MODULE (module));
120
121 if (anjuta_c_module_get_last_error (module, error))
122 {
123 /* Avoid memory leak in case of error*/
124 g_strfreev (pieces);
125
126 return NULL;
127 }
128 g_hash_table_insert (plugin_in_path, g_strdup (pieces[0]), module);
129 }
130 else
131 {
132 module = NULL;
133 }
134
135 /* Find plugin type */
136 if (pieces[1] == NULL)
137 {
138 g_strfreev (pieces);
139 g_set_error (error, IANJUTA_PLUGIN_FACTORY_ERROR,
140 IANJUTA_PLUGIN_FACTORY_MISSING_TYPE,
141 _("Missing type defined by plugin %s"), anjuta_plugin_handle_get_name (handle));
142 return NULL;
143 }
144 type = g_type_from_name (pieces[1]);
145 if (type == G_TYPE_INVALID)
146 {
147 g_set_error (error, IANJUTA_PLUGIN_FACTORY_ERROR,
148 IANJUTA_PLUGIN_FACTORY_INVALID_TYPE,
149 _("plugin %s fails to register type %s"), anjuta_plugin_handle_get_name (handle), pieces[1]);
150 g_strfreev (pieces);
151
152 return NULL;
153 }
154 g_strfreev (pieces);
155
156 /* Create plugin */
157 plugin = (AnjutaPlugin *)g_object_new (type, "shell", shell, NULL);
158
159 if ((module != NULL) && (anjuta_plugin_handle_get_resident(handle) == FALSE))
160 {
161 /* This module can be unloaded when not needed */
162 g_type_module_unuse (G_TYPE_MODULE (module));
163 }
164
165 return plugin;
166 }
167
168 /* IAnjutaPluginFactory interface
169 *---------------------------------------------------------------------------*/
170
171 static AnjutaPlugin*
ianjuta_c_plugin_factory_new_plugin(IAnjutaPluginFactory * ifactory,AnjutaPluginHandle * handle,AnjutaShell * shell,GError ** error)172 ianjuta_c_plugin_factory_new_plugin (IAnjutaPluginFactory *ifactory, AnjutaPluginHandle *handle, AnjutaShell *shell, GError **error)
173 {
174 AnjutaCPluginFactory *factory = ANJUTA_C_PLUGIN_FACTORY (ifactory);
175
176 return anjuta_c_plugin_factory_create_plugin (factory, handle, shell, error);
177 }
178
179 static void
ianjuta_c_plugin_factory_iface_init(IAnjutaPluginFactoryIface * iface)180 ianjuta_c_plugin_factory_iface_init (IAnjutaPluginFactoryIface *iface)
181 {
182 iface->new_plugin = ianjuta_c_plugin_factory_new_plugin;
183 }
184
185
186 /* GObject functions
187 *---------------------------------------------------------------------------*/
188
189 /* dispose is the first destruction step. It is used to unref object created
190 * with instance_init in order to break reference counting cycles. This
191 * function could be called several times. All function should still work
192 * after this call. It has to called its parents.*/
193
194 static void
anjuta_c_plugin_factory_dispose(GObject * object)195 anjuta_c_plugin_factory_dispose (GObject *object)
196 {
197 AnjutaCPluginFactory *factory = ANJUTA_C_PLUGIN_FACTORY (object);
198
199 g_hash_table_unref (factory->loaded_plugins);
200 factory->loaded_plugins = NULL;
201
202 G_OBJECT_CLASS (anjuta_c_plugin_factory_parent_class)->dispose (object);
203 }
204
205 static void
anjuta_c_plugin_factory_class_init(AnjutaCPluginFactoryClass * klass)206 anjuta_c_plugin_factory_class_init (AnjutaCPluginFactoryClass *klass)
207 {
208 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
209
210 gobject_class->dispose = anjuta_c_plugin_factory_dispose;
211 }
212
213 static void
anjuta_c_plugin_factory_init(AnjutaCPluginFactory * factory)214 anjuta_c_plugin_factory_init (AnjutaCPluginFactory *factory)
215 {
216 factory->loaded_plugins = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_hash_table_unref);
217 }
218
219 /* Creation and Destruction
220 *---------------------------------------------------------------------------*/
221 /**
222 * anjuta_c_plugin_factory_new:
223 *
224 * Create a new #AnjutaCPluginFactory object.
225 *
226 * Return value: a new #AnjutaCPluginFactory object.
227 */
228 AnjutaCPluginFactory*
anjuta_c_plugin_factory_new(void)229 anjuta_c_plugin_factory_new (void)
230 {
231 AnjutaCPluginFactory *factory;
232
233 factory = g_object_new (ANJUTA_TYPE_C_PLUGIN_FACTORY, NULL);
234
235 return factory;
236 }
237
238 /**
239 * anjuta_c_plugin_factory_free:
240 * @factory: a #AnjutaCPluginFactory
241 *
242 * Delete a #AnjutaCPluginFactory object.
243 */
244 void
anjuta_c_plugin_factory_free(AnjutaCPluginFactory * factory)245 anjuta_c_plugin_factory_free (AnjutaCPluginFactory *factory)
246 {
247 g_object_unref (G_OBJECT(factory));
248 }
249