1 /** \file
2 * The implementation of pluggable objects into Inkscape.
3 *
4 * Author: Ted Gould <ted@gould.cx>
5 * Copyright (c) 2004-2005
6 *
7 * This code is licensed under the GNU GPL. See COPYING for details.
8 *
9 * This file implements loadable modules for Inkscape.
10 */
11 #ifdef HAVE_CONFIG_H
12 # include "config.h"
13 #endif
14 #include <stdio.h>
16 #include <glibmm/module.h>
17 #include <glibmm/fileutils.h>
18 #include <path-prefix.h>
19 #include "extension/extension.h"
20 #include "xml/repr.h"
21 #include "plugin.h"
22 #include "plugin-link.h"
24 namespace Inkscape {
25 namespace Extension {
26 namespace Implementation {
28 /** \brief Create an object by nulling everything out. */
29 Plugin::Plugin(void)
30 {
31 _module = NULL;
32 _symTable = NULL;
34 return;
35 }
37 /**
38 \brief Oh, so someone actually wants to use this plugin! We better
39 go and grab it then!
40 \param module Unused except to pass to the plugin's load function.
41 \return Whether the load was successful. Hopefully always TRUE.
43 Okay, first things first, are modules supported on this platform? That
44 is a good first check. Also, is this plugin already loaded? If so
45 don't reload it.
47 If all those are true we need to figure out the filename that needs
48 to be loaded. This involves going through the definition of the plugin
49 for the \c name field. It is then run though the \c build_path function
50 to add the .so or .dll on the end. The path that is used is the
51 \c INKSCAPE_PLUGINDIR.
53 The module is then loaded into RAM by Glib. I'm sure there is lots
54 of magic involved here -- but we don't have to worry about it, we
55 just check to make sure it worked.
57 After it is loaded into memory the function lookup table is grabbed
58 and then the load function for the plugin is called.
59 */
60 bool
61 Plugin::load(Inkscape::Extension::Extension *module)
62 {
63 if (!Glib::Module::get_supported()) {
64 return FALSE;
65 }
67 if (module->loaded()) {
68 return TRUE;
69 }
71 Inkscape::XML::Node * child_repr = sp_repr_children(module->get_repr());
72 const gchar * name = NULL;
73 while (child_repr != NULL) {
74 if (!strcmp(child_repr->name(), "plugin")) {
75 child_repr = sp_repr_children(child_repr);
76 while (child_repr != NULL) {
77 if (!strcmp(child_repr->name(), "name")) {
78 name = sp_repr_children(child_repr)->content();
79 }
80 child_repr = sp_repr_next(child_repr);
81 }
82 }
83 child_repr = sp_repr_next(child_repr);
84 }
86 if (name == NULL) {
87 return FALSE;
88 }
90 std::string path = Glib::Module::build_path(INKSCAPE_PLUGINDIR, name);
91 // std::cout << "Load path: " << path << std::endl;
92 _module = new Glib::Module(path);
94 if (!(bool)_module || _module == NULL) {
95 printf("Loading failed\n");
96 return FALSE;
97 }
99 /* Grab symbols */
100 void * voidpntr;
101 if (!_module->get_symbol(INKSCAPE_PLUGIN_NAME_STR, voidpntr)) {
102 // printf("Error loading library\n");
103 // std::cout << "Last error: " << _module->get_last_error() << std::endl;
104 return FALSE;
105 }
106 _symTable = (inkscape_plugin_function_table *)voidpntr;
108 if (_symTable->version != INKSCAPE_PLUGIN_VERSION) {
109 /* Someday this could adapt older versions so that we could
110 be compatible -- but not today */
111 return FALSE;
112 }
114 if (_symTable->load != NULL) {
115 return (bool)_symTable->load((inkscape_extension *)module);
116 }
118 return TRUE;
119 }
121 /**
122 \brief No one is interested in this plugin for now. It is removed
123 to save memory.
124 \param module The module of this implementation, passed to unload.
125 \return None.
127 Call the unload function of the plugin, then delete the symbol table
128 and the module itself. Put everything back to NULL.
129 */
130 void
131 Plugin::unload(Inkscape::Extension::Extension *module)
132 {
133 _symTable->unload((inkscape_extension *)module);
134 _symTable = NULL;
135 delete _module;
136 _module = NULL;
137 return;
138 }
140 /**
141 \brief Just check to make sure everything exists. This makes sure
142 that the loadable file exits.
143 \param module Unused.
144 \return The status of the check. TRUE means that it passed.
146 This function builds the path name out of the XML definition of the
147 plugin. It does this by looking for the \c name parameter. It then
148 uses \c build_path to add the .so or .dll and adds in the \c INKSCAPE_PLUGINDIR
149 to the front of it. Then the \c file_test function is used to make
150 sure it exists.
151 */
152 bool
153 Plugin::check(Inkscape::Extension::Extension *module)
154 {
155 Inkscape::XML::Node * child_repr = sp_repr_children(module->get_repr());
156 const gchar * name = NULL;
157 while (child_repr != NULL) {
158 if (!strcmp(child_repr->name(), "plugin")) {
159 child_repr = sp_repr_children(child_repr);
160 while (child_repr != NULL) {
161 if (!strcmp(child_repr->name(), "name")) {
162 name = sp_repr_children(child_repr)->content();
163 }
164 child_repr = sp_repr_next(child_repr);
165 }
166 }
167 child_repr = sp_repr_next(child_repr);
168 }
170 if (name == NULL) {
171 return FALSE;
172 }
174 std::string path = Glib::Module::build_path(INKSCAPE_PLUGINDIR, name);
175 // std::cout << "Path: " << path << std::endl;
176 if (!Glib::file_test(path, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_EXECUTABLE)) {
177 // std::cout << "Failed!" << std::endl;
178 return FALSE;
179 }
181 // std::cout << "No Problem." << std::endl;
182 return TRUE;
183 }
185 Gtk::Widget *
186 Plugin::prefs_input(Inkscape::Extension::Input *module, gchar const *filename)
187 {
188 return Inkscape::Extension::Implementation::Implementation::prefs_input(module, filename);
189 }
191 /*
192 \brief Function to call the open in the plugin.
193 \param module Passed on
194 \param filename Passed on
195 \return The document that is opened or NULL for error.
197 This function looks in the symbol table to see if there is an open
198 function. If there is, it is called, otherwise the standard implementation
199 function is used instead.
200 */
201 SPDocument *
202 Plugin::open(Inkscape::Extension::Input *module, gchar const *filename)
203 {
204 if (_symTable->open != NULL) {
205 return _symTable->open((inkscape_extension *)module, filename);
206 } else {
207 return Inkscape::Extension::Implementation::Implementation::open(module, filename);
208 }
209 }
211 Gtk::Widget *
212 Plugin::prefs_output(Inkscape::Extension::Output *module)
213 {
214 return Inkscape::Extension::Implementation::Implementation::prefs_output(module);
215 }
217 void
218 Plugin::save(Inkscape::Extension::Output *module, SPDocument *doc, gchar const *filename)
219 {
220 return Inkscape::Extension::Implementation::Implementation::save(module, doc, filename);
221 }
223 Gtk::Widget *
224 Plugin::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View * view)
225 {
226 if (_symTable->prefs_effect != NULL) {
227 return _symTable->prefs_effect((inkscape_extension *)module, view);
228 } else {
229 return Inkscape::Extension::Implementation::Implementation::prefs_effect(module, view);
230 }
231 }
233 void
234 Plugin::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document)
235 {
236 if (_symTable->effect != NULL) {
237 return _symTable->effect((inkscape_extension *)module, document);
238 } else {
239 return Inkscape::Extension::Implementation::Implementation::effect(module, document);
240 }
241 }
243 unsigned
244 Plugin::setup(Inkscape::Extension::Print *module)
245 {
246 return Inkscape::Extension::Implementation::Implementation::setup(module);
247 }
249 unsigned
250 Plugin::set_preview(Inkscape::Extension::Print *module)
251 {
252 return Inkscape::Extension::Implementation::Implementation::set_preview(module);
253 }
255 unsigned
256 Plugin::begin(Inkscape::Extension::Print *module, SPDocument *doc)
257 {
258 return Inkscape::Extension::Implementation::Implementation::begin(module, doc);
259 }
261 unsigned
262 Plugin::finish(Inkscape::Extension::Print *module)
263 {
264 return Inkscape::Extension::Implementation::Implementation::finish(module);
265 }
267 bool
268 Plugin::textToPath(Inkscape::Extension::Print *ext)
269 {
270 return Inkscape::Extension::Implementation::Implementation::finish(ext);
271 }
273 unsigned
274 Plugin::bind(Inkscape::Extension::Print *module, NRMatrix const *transform, float opacity)
275 {
276 return Inkscape::Extension::Implementation::Implementation::bind(module, transform, opacity);
277 }
279 unsigned
280 Plugin::release(Inkscape::Extension::Print *module)
281 {
282 return Inkscape::Extension::Implementation::Implementation::release(module);
283 }
285 unsigned
286 Plugin::comment(Inkscape::Extension::Print *module, const char * comment)
287 {
288 return Inkscape::Extension::Implementation::Implementation::comment(module,comment);
289 }
291 unsigned
292 Plugin::fill(Inkscape::Extension::Print *module, NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
293 {
294 return Inkscape::Extension::Implementation::Implementation::fill(module, bpath, ctm, style, pbox, dbox, bbox);
295 }
297 unsigned
298 Plugin::stroke(Inkscape::Extension::Print *module, NRBPath const *bpath, NRMatrix const *transform, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
299 {
300 return Inkscape::Extension::Implementation::Implementation::stroke(module, bpath, transform, style, pbox, dbox, bbox);
301 }
303 unsigned
304 Plugin::image(Inkscape::Extension::Print *module, unsigned char *px, unsigned int w, unsigned int h, unsigned int rs, NRMatrix const *transform, SPStyle const *style)
305 {
306 return Inkscape::Extension::Implementation::Implementation::image(module, px, w, h, rs, transform, style);
307 }
309 unsigned
310 Plugin::text(Inkscape::Extension::Print *module, char const *text, NR::Point p, SPStyle const *style)
311 {
312 return Inkscape::Extension::Implementation::Implementation::text(module, text, p, style);
313 }
315 } /* namespace Implementation */
316 } /* namespace Extension */
317 } /* namespace Inkscape */
319 /*
320 Local Variables:
321 mode:c++
322 c-file-style:"stroustrup"
323 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
324 indent-tabs-mode:nil
325 fill-column:99
326 End:
327 */
328 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :