1 /*
2 * peas-plugin-loader-c.c
3 * This file is part of libpeas
4 *
5 * Copyright (C) 2008 - Jesse van den Kieboom
6 *
7 * libpeas is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * libpeas 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 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27
28 #include "peas-plugin-loader-c.h"
29
30 #include "peas-extension-base.h"
31 #include "peas-object-module.h"
32 #include "peas-plugin-info-priv.h"
33
34 typedef struct {
35 GMutex lock;
36
37 GHashTable *loaded_plugins;
38 } PeasPluginLoaderCPrivate;
39
40 G_DEFINE_TYPE_WITH_PRIVATE (PeasPluginLoaderC,
41 peas_plugin_loader_c,
42 PEAS_TYPE_PLUGIN_LOADER)
43
44 #define GET_PRIV(o) \
45 (peas_plugin_loader_c_get_instance_private (o))
46
47 static GQuark quark_extension_type = 0;
48 static const gchar *intern_plugin_info = NULL;
49
50 static gboolean
peas_plugin_loader_c_load(PeasPluginLoader * loader,PeasPluginInfo * info)51 peas_plugin_loader_c_load (PeasPluginLoader *loader,
52 PeasPluginInfo *info)
53 {
54 PeasPluginLoaderC *cloader = PEAS_PLUGIN_LOADER_C (loader);
55 PeasPluginLoaderCPrivate *priv = GET_PRIV (cloader);
56
57 g_mutex_lock (&priv->lock);
58
59 if (!g_hash_table_lookup_extended (priv->loaded_plugins,
60 info->filename,
61 NULL, (gpointer *) &info->loader_data))
62 {
63 const gchar *module_name, *module_dir;
64
65 module_name = peas_plugin_info_get_module_name (info);
66 module_dir = peas_plugin_info_get_module_dir (info);
67
68 if (info->embedded != NULL)
69 {
70 info->loader_data = peas_object_module_new_embedded (module_name,
71 info->embedded);
72 }
73 else
74 {
75 /* Force all C modules to be resident in case they
76 * use libraries that do not deal well with reloading.
77 * Furthermore, we use local linkage to improve module isolation.
78 */
79 info->loader_data = peas_object_module_new_full (module_name,
80 module_dir,
81 TRUE, TRUE);
82 }
83
84 if (!g_type_module_use (G_TYPE_MODULE (info->loader_data)))
85 g_clear_object (&info->loader_data);
86
87 g_hash_table_insert (priv->loaded_plugins,
88 g_strdup (info->filename), info->loader_data);
89 }
90
91 g_mutex_unlock (&priv->lock);
92 return info->loader_data != NULL;
93 }
94
95 static void
peas_plugin_loader_c_unload(PeasPluginLoader * loader,PeasPluginInfo * info)96 peas_plugin_loader_c_unload (PeasPluginLoader *loader,
97 PeasPluginInfo *info)
98 {
99 /* Don't bother unloading the plugin's
100 * GTypeModule as it is always resident
101 */
102 info->loader_data = NULL;
103 }
104
105 static gboolean
peas_plugin_loader_c_provides_extension(PeasPluginLoader * loader,PeasPluginInfo * info,GType exten_type)106 peas_plugin_loader_c_provides_extension (PeasPluginLoader *loader,
107 PeasPluginInfo *info,
108 GType exten_type)
109 {
110 return peas_object_module_provides_object (info->loader_data, exten_type);
111 }
112
113 static PeasExtension *
peas_plugin_loader_c_create_extension(PeasPluginLoader * loader,PeasPluginInfo * info,GType exten_type,guint n_parameters,GParameter * parameters)114 peas_plugin_loader_c_create_extension (PeasPluginLoader *loader,
115 PeasPluginInfo *info,
116 GType exten_type,
117 guint n_parameters,
118 GParameter *parameters)
119 {
120 GParameter *exten_parameters;
121 gpointer instance;
122
123 /* We want to add a "plugin-info" property so we can pass it to
124 * the extension if it inherits from PeasExtensionBase. No need to
125 * actually "duplicate" the GValues, a memcpy is sufficient as the
126 * source GValues are longer lived than our local copy.
127 */
128 exten_parameters = g_newa (GParameter, n_parameters + 1);
129 memcpy (exten_parameters, parameters, sizeof (GParameter) * n_parameters);
130
131 /* Initialize our additional property.
132 * If the instance does not have a plugin-info property
133 * then PeasObjectModule will remove the property.
134 */
135 exten_parameters[n_parameters].name = intern_plugin_info;
136 memset (&exten_parameters[n_parameters].value, 0, sizeof (GValue));
137 g_value_init (&exten_parameters[n_parameters].value, PEAS_TYPE_PLUGIN_INFO);
138 g_value_set_boxed (&exten_parameters[n_parameters].value, info);
139
140 instance = peas_object_module_create_object (info->loader_data,
141 exten_type,
142 n_parameters + 1,
143 exten_parameters);
144
145 g_value_unset (&exten_parameters[n_parameters].value);
146
147 if (instance == NULL)
148 return NULL;
149
150 g_return_val_if_fail (G_IS_OBJECT (instance), NULL);
151 g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (instance, exten_type), NULL);
152
153 /* We have to remember which interface we are instantiating
154 * for the deprecated peas_extension_get_extension_type().
155 */
156 g_object_set_qdata (instance, quark_extension_type,
157 GSIZE_TO_POINTER (exten_type));
158
159 return instance;
160 }
161
162 static void
peas_plugin_loader_c_init(PeasPluginLoaderC * cloader)163 peas_plugin_loader_c_init (PeasPluginLoaderC *cloader)
164 {
165 PeasPluginLoaderCPrivate *priv = GET_PRIV (cloader);
166
167 g_mutex_init (&priv->lock);
168
169 /* loaded_plugins maps PeasPluginInfo:filename to a PeasObjectModule */
170 priv->loaded_plugins = g_hash_table_new_full (g_str_hash, g_str_equal,
171 g_free, NULL);
172 }
173
174 static void
peas_plugin_loader_c_finalize(GObject * object)175 peas_plugin_loader_c_finalize (GObject *object)
176 {
177 PeasPluginLoaderC *cloader = PEAS_PLUGIN_LOADER_C (object);
178 PeasPluginLoaderCPrivate *priv = GET_PRIV (cloader);
179
180 g_mutex_clear (&priv->lock);
181
182 g_hash_table_destroy (priv->loaded_plugins);
183
184 G_OBJECT_CLASS (peas_plugin_loader_c_parent_class)->finalize (object);
185 }
186
187 static void
peas_plugin_loader_c_class_init(PeasPluginLoaderCClass * klass)188 peas_plugin_loader_c_class_init (PeasPluginLoaderCClass *klass)
189 {
190 GObjectClass *object_class = G_OBJECT_CLASS (klass);
191 PeasPluginLoaderClass *loader_class = PEAS_PLUGIN_LOADER_CLASS (klass);
192
193 quark_extension_type = g_quark_from_static_string ("peas-extension-type");
194 intern_plugin_info = g_intern_static_string ("plugin-info");
195
196 object_class->finalize = peas_plugin_loader_c_finalize;
197
198 loader_class->load = peas_plugin_loader_c_load;
199 loader_class->unload = peas_plugin_loader_c_unload;
200 loader_class->provides_extension = peas_plugin_loader_c_provides_extension;
201 loader_class->create_extension = peas_plugin_loader_c_create_extension;
202 }
203
204 /*
205 * peas_plugin_loader_c_new:
206 *
207 * Return a new instance of #PeasPluginLoaderC.
208 *
209 * Returns: a new instance of #PeasPluginLoaderC.
210 */
211 PeasPluginLoader *
peas_plugin_loader_c_new(void)212 peas_plugin_loader_c_new (void)
213 {
214 return PEAS_PLUGIN_LOADER (g_object_new (PEAS_TYPE_PLUGIN_LOADER_C, NULL));
215 }
216