1 /*
2  * * Copyright (C) 2006-2011 Anders Brander <anders@brander.dk>,
3  * * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19 
20 #include <gmodule.h>
21 #include "rs-plugin.h"
22 
23 struct _RSPlugin {
24 	GTypeModule parent_instance;
25 
26 	gchar *filename;
27 	GModule *library;
28 
29 	void (*load)(RSPlugin *plugin);
30 	void (*unload)(RSPlugin *plugin);
31 };
32 
33 struct _RSPluginClass {
34 	GTypeModuleClass  parent_class;
35 };
36 
37 enum {
38 	PROP_0,
39 	PROP_FILENAME
40 };
41 
42 static void rs_plugin_finalize (GObject *object);
43 static void rs_plugin_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec);
44 static void rs_plugin_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec);
45 static gboolean rs_plugin_load_module (GTypeModule  *gmodule);
46 static void rs_plugin_unload_module (GTypeModule  *gmodule);
47 
48 G_DEFINE_TYPE(RSPlugin, rs_plugin, G_TYPE_TYPE_MODULE);
49 
50 static void
rs_plugin_class_init(RSPluginClass * klass)51 rs_plugin_class_init(RSPluginClass *klass)
52 {
53 	GObjectClass *object_class = G_OBJECT_CLASS(klass);
54 	GTypeModuleClass *type_module_class = G_TYPE_MODULE_CLASS(klass);
55 
56 	object_class->finalize = rs_plugin_finalize;
57 	object_class->get_property = rs_plugin_get_property;
58 	object_class->set_property = rs_plugin_set_property;
59 
60 	type_module_class->load = rs_plugin_load_module;
61 	type_module_class->unload  = rs_plugin_unload_module;
62 
63 	g_object_class_install_property(object_class,
64 		PROP_FILENAME, g_param_spec_string (
65 			"filename",
66 			"Filename",
67 			"The filaname of the plugin",
68 			NULL,
69 			G_PARAM_READWRITE |G_PARAM_CONSTRUCT_ONLY)
70 	);
71 }
72 
73 static void
rs_plugin_init(RSPlugin * plugin)74 rs_plugin_init(RSPlugin *plugin)
75 {
76 	plugin->filename = NULL;
77 	plugin->library = NULL;
78 	plugin->load = NULL;
79 	plugin->unload = NULL;
80 }
81 
82 static void
rs_plugin_finalize(GObject * object)83 rs_plugin_finalize(GObject *object)
84 {
85 	RSPlugin *plugin = RS_PLUGIN(object);
86 
87 	g_free(plugin->filename);
88 
89 	G_OBJECT_CLASS(rs_plugin_parent_class)->finalize(object);
90 }
91 
92 static void
rs_plugin_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)93 rs_plugin_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec)
94 {
95 	RSPlugin *plugin = RS_PLUGIN(object);
96 
97 	switch (param_id)
98 	{
99 		case PROP_FILENAME:
100 			g_value_set_string(value, plugin->filename);
101 			break;
102 		default:
103 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
104 			break;
105 	}
106 }
107 
108 static void
rs_plugin_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)109 rs_plugin_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec)
110 {
111 	RSPlugin *plugin = RS_PLUGIN(object);
112 
113 	switch (param_id)
114 	{
115 		case PROP_FILENAME:
116 			g_free (plugin->filename);
117 			plugin->filename = g_value_dup_string (value);
118 			break;
119 		default:
120 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
121 			break;
122 	}
123 }
124 
125 static gboolean
rs_plugin_load_module(GTypeModule * gmodule)126 rs_plugin_load_module(GTypeModule *gmodule)
127 {
128 	RSPlugin *plugin = RS_PLUGIN(gmodule);
129 
130 	g_assert(G_IS_TYPE_MODULE(gmodule));
131 	g_assert(RS_IS_PLUGIN(plugin));
132 
133 	g_assert(plugin->filename != NULL);
134 
135 	plugin->library = g_module_open(plugin->filename, 0);
136 
137 	if (!plugin->library)
138 	{
139 		g_printerr ("%s\n", g_module_error ());
140 		return FALSE;
141 	}
142 
143 	if (!g_module_symbol(plugin->library, "rs_plugin_load", (gpointer *) &plugin->load))
144 	{
145 		g_printerr ("%s\n", g_module_error ());
146 		g_module_close (plugin->library);
147 		return FALSE;
148 	}
149 
150 	/* This is not required from plugins - YET! */
151 	if (!g_module_symbol(plugin->library, "rs_plugin_unload", (gpointer *) &plugin->unload))
152 		plugin->unload = NULL;
153 
154 	/* Execute plugin load method */
155 	plugin->load (plugin);
156 
157 	/* We don't support unloading of modules - FOR NOW - make sure it never happens */
158 	g_module_make_resident(plugin->library);
159 
160 	return TRUE;
161 }
162 
163 static void
rs_plugin_unload_module(GTypeModule * gmodule)164 rs_plugin_unload_module (GTypeModule *gmodule)
165 {
166 	RSPlugin *plugin = RS_PLUGIN(gmodule);
167 
168 	g_assert(G_IS_TYPE_MODULE(gmodule));
169 	g_assert(RS_IS_PLUGIN(plugin));
170 
171 	if (plugin->unload)
172 		plugin->unload (plugin);
173 
174 	g_module_close (plugin->library);
175 	plugin->library = NULL;
176 
177 	plugin->load = NULL;
178 	plugin->unload = NULL;
179 }
180 
181 RSPlugin *
rs_plugin_new(const gchar * filename)182 rs_plugin_new (const gchar *filename)
183 {
184 	RSPlugin *plugin;
185 
186 	g_assert(filename != NULL);
187 
188 	plugin = g_object_new(RS_TYPE_PLUGIN, "filename", filename, NULL);
189 
190 	return plugin;
191 }
192