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