1 : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 : /*
3 : * plugin.c
4 : * heraia - an hexadecimal file editor and analyser based on ghex
5 : *
6 : * (C) Copyright 2007 Olivier Delhomme
7 : * e-mail : heraia@delhomme.org
8 : * URL : http://heraia.tuxfamily.org
9 : *
10 : * This program is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * This program is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU General Public License
21 : * along with this program; if not, write to the Free Software
22 : * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 : */
24 :
25 : #include "heraia_types.h"
26 :
27 : static heraia_plugin_t *get_plugin_handle(heraia_window_t *main_window, heraia_plugin_t *plugin,
28 : const gchar *full_filename, const gchar *filename);
29 : static heraia_plugin_t *get_plugin_init_symbol(heraia_window_t *main_window, heraia_plugin_t *plugin);
30 : static void init_plugin(heraia_window_t *main_window, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb);
31 : static void load_one_plugin(heraia_window_t *main_window, const gchar *filename, guint plugins_nb);
32 :
33 : /**
34 : * Says whether the system can handle plugins (or not)
35 : */
36 : gboolean plugin_capable(void)
37 1 : {
38 1 : return g_module_supported();
39 : }
40 :
41 : /**
42 : * Creates a new empty plugin
43 : * it may be initialised by
44 : * the plugin itself !
45 : */
46 : heraia_plugin_t *new_plugin(void)
47 1 : {
48 1 : heraia_plugin_t *new = NULL;
49 :
50 1 : new = (heraia_plugin_t *) g_malloc0(sizeof(heraia_plugin_t));
51 :
52 1 : new->state = PLUGIN_STATE_NEW; /* The plugin state */
53 1 : new->handle = NULL; /* The module handle */
54 1 : new->path = NULL; /* The path to the plugin */
55 1 : new->filename = NULL;
56 1 : new->info = (plugin_info_t *) g_malloc0(sizeof(plugin_info_t)); /* The plugin information */
57 1 : new->filter = (plugin_filter_t *) g_malloc0(sizeof(plugin_filter_t)); /* The plugin filter */
58 1 : new->error = NULL;
59 1 : new->extra = NULL; /* Plugin-specific data */
60 :
61 : /* Called when the application initialy starts up */
62 1 : new->init_proc = NULL;
63 : /* Called when the application exits */
64 1 : new->quit_proc = NULL;
65 : /* Called to run a miscellaneous thing everytime the plugin is called */
66 1 : new->run_proc = NULL;
67 :
68 1 : return new;
69 :
70 : }
71 :
72 : /**
73 : * free an unused plugin
74 : */
75 : void free_plugin(heraia_plugin_t *plugin)
76 0 : {
77 0 : if (plugin != NULL)
78 : {
79 0 : if (plugin->handle != NULL)
80 0 : g_module_close(plugin->handle);
81 0 : if (plugin->info != NULL)
82 : {
83 0 : g_free(plugin->info->name);
84 0 : g_free(plugin->info->version);
85 0 : g_free(plugin->info->summary);
86 0 : g_free(plugin->info->description);
87 0 : g_free(plugin->info->author);
88 0 : g_free(plugin->info->homepage);
89 0 : g_free(plugin->info);
90 : }
91 0 : if (plugin->filter != NULL)
92 : {
93 0 : g_free(plugin->filter->extensions);
94 0 : g_free(plugin->filter);
95 : }
96 0 : g_free(plugin->path);
97 0 : g_free(plugin->filename);
98 0 : g_free(plugin->error);
99 0 : g_free(plugin->extra);
100 :
101 0 : g_free(plugin);
102 : }
103 0 : }
104 :
105 : /**
106 : * Here we try to get a handle for the Gmodule referenced by full_filename
107 : */
108 : static heraia_plugin_t *get_plugin_handle(heraia_window_t *main_window, heraia_plugin_t *plugin,
109 : const gchar *full_filename, const gchar *filename)
110 : {
111 1 : if (plugin != NULL)
112 : {
113 :
114 1 : plugin->handle = g_module_open(full_filename, G_MODULE_BIND_MASK);
115 :
116 1 : if (plugin->handle == NULL)
117 : {
118 0 : log_message(main_window, G_LOG_LEVEL_WARNING, "Could not open plugin %s - %s", filename, g_module_error());
119 : }
120 : }
121 :
122 1 : return plugin;
123 : }
124 :
125 : /**
126 : * If the handle is ok, we want to have the heraia_plugin_init function (to call it)
127 : * in order to init the plugin (by itself)
128 : */
129 : static heraia_plugin_t *get_plugin_init_symbol(heraia_window_t *main_window, heraia_plugin_t *plugin)
130 : {
131 : heraia_plugin_t *(*heraia_plugin_init)(heraia_plugin_t *);
132 1 : gboolean get_symbol = FALSE;
133 :
134 1 : if (plugin != NULL && plugin->handle != NULL)
135 : {
136 1 : get_symbol = g_module_symbol(plugin->handle, "heraia_plugin_init", (gpointer *)(&heraia_plugin_init));
137 :
138 1 : if (get_symbol == FALSE)
139 : {
140 0 : log_message(main_window, G_LOG_LEVEL_WARNING, "%s", g_module_error());
141 0 : free_plugin(plugin);
142 0 : return NULL;
143 : }
144 : else
145 : {
146 : /* the plugins inits itself here */
147 1 : plugin = heraia_plugin_init(plugin);
148 1 : return plugin;
149 : }
150 : }
151 : else
152 : {
153 0 : free_plugin(plugin);
154 0 : return NULL;
155 : }
156 : }
157 :
158 : /**
159 : * finalising initialisation : if everything went fine, the plugin is added to the
160 : * plugin list and a menu entry is created in the Plugins menu
161 : */
162 : static void init_plugin(heraia_window_t *main_window, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
163 : {
164 1 : if (plugin != NULL)
165 : {
166 1 : plugin->info->id = plugins_nb;
167 1 : main_window->plugins_list = g_list_append(main_window->plugins_list, plugin);
168 1 : log_message(main_window, G_LOG_LEVEL_INFO, "plugin %s loaded.", filename);
169 1 : plugin->init_proc(main_window);
170 1 : if (plugin->info->type == HERAIA_PLUGIN_ACTION)
171 : {
172 1 : add_entry_to_plugins_menu(main_window, plugin);
173 : }
174 :
175 : }
176 : }
177 :
178 : /**
179 : * Here we manage to load one plugin at a time (and this is really enough !)
180 : */
181 : static void load_one_plugin(heraia_window_t *main_window, const gchar *filename, guint plugins_nb)
182 4 : {
183 4 : const gchar *full_filename = NULL;
184 4 : heraia_plugin_t *plugin = NULL;
185 4 : gchar *ext = g_strdup_printf(".%s", G_MODULE_SUFFIX); /* system dependent suffix */
186 :
187 4 : full_filename = g_build_filename(PLUGINS_DIR, filename, NULL);
188 :
189 : /* Make sure we do load the module named .so, .dll or .sl depending on the OS type */
190 8 : if ( (g_file_test(full_filename, G_FILE_TEST_IS_DIR) == FALSE) &&
191 4 : (strcmp(strrchr(filename, '.'), ext) == 0)
192 : )
193 : {
194 1 : plugin = new_plugin();
195 1 : plugin->path = g_strdup_printf("%s", PLUGINS_DIR);
196 1 : plugin->filename = g_strdup_printf("%s", filename);
197 :
198 1 : plugin = get_plugin_handle(main_window, plugin, full_filename, filename);
199 1 : plugin = get_plugin_init_symbol(main_window, plugin);
200 :
201 : init_plugin(main_window, plugin, filename, plugins_nb);
202 : }
203 4 : }
204 :
205 :
206 : /**
207 : * looks at the plugins dir(s) and loads
208 : * the needed plugins (all ;-) (one at a time !!)
209 : */
210 : void load_plugins(heraia_window_t *main_window)
211 1 : {
212 1 : GDir *plugins_dir = NULL;
213 1 : GError *error = NULL;
214 1 : const gchar *filename = NULL;
215 1 : unsigned int plugins_nb = 0;
216 :
217 : /* Register all shared plugins (plugins_dir) (-DPLUGINS_DIR) */
218 : /* This may be a config file option later ... */
219 1 : plugins_dir = g_dir_open(PLUGINS_DIR, 0, &error);
220 :
221 1 : if (plugins_dir == NULL) /* error while openning the plugins directory */
222 : {
223 0 : log_message(main_window, G_LOG_LEVEL_WARNING, "%s", error->message);
224 0 : g_error_free(error);
225 : }
226 : else
227 : {
228 5 : while ((filename = g_dir_read_name(plugins_dir)) != NULL)
229 : {
230 4 : load_one_plugin(main_window, filename, ++plugins_nb);
231 : }
232 1 : g_dir_close(plugins_dir);
233 : }
234 1 : }
235 :
236 : /**
237 : * adds a menu entry to the plugin menu
238 : * adds a signal handler when the menu is toggled
239 : */
240 : void add_entry_to_plugins_menu(heraia_window_t *main_window, heraia_plugin_t *plugin)
241 1 : {
242 : /* Creates the menu entry (a GtkCheckMenuItem) */
243 1 : plugin->cmi_entry = GTK_CHECK_MENU_ITEM(gtk_check_menu_item_new_with_label(plugin->info->name));
244 :
245 : /* Append this menu entry to the menu */
246 1 : gtk_menu_shell_append(GTK_MENU_SHELL(heraia_get_widget(main_window->xmls->main, "plugins_menu")), GTK_WIDGET(plugin->cmi_entry));
247 :
248 : /* Connect the menu entry toggled signal to the run_proc function of the plugin */
249 1 : g_signal_connect(G_OBJECT(plugin->cmi_entry), "toggled", G_CALLBACK(plugin->run_proc), main_window);
250 :
251 : /* Shows the menu entry (so we may toggle it!) */
252 1 : gtk_widget_show(GTK_WIDGET(plugin->cmi_entry));
253 1 : }
254 :
255 : /**
256 : * Finds the desired plugin by its name and return the plugin structure or NULL
257 : */
258 : heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
259 1 : {
260 1 : GList *list = g_list_first(plugins_list);
261 1 : heraia_plugin_t *plugin = NULL;
262 1 : gboolean stop = FALSE;
263 :
264 3 : while (list != NULL && stop != TRUE)
265 : {
266 1 : plugin = (heraia_plugin_t *) list->data;
267 1 : if (plugin != NULL && plugin->info != NULL)
268 : {
269 1 : if (strcmp(plugin->info->name, name) == 0)
270 1 : stop = TRUE;
271 : }
272 1 : list = list->next;
273 : }
274 1 : if (stop == TRUE)
275 1 : return plugin;
276 : else
277 0 : return NULL;
278 : }
279 :
280 :
281 : /**
282 : * Loads the glade xml file that describes the plugin (.glade suffix)
283 : * tries the paths found in the location_list
284 : */
285 : gboolean load_plugin_glade_xml(heraia_window_t *main_window, heraia_plugin_t *plugin)
286 1 : {
287 1 : gchar *filename = NULL;
288 :
289 1 : filename = g_strdup_printf("%s.glade", plugin->info->name);
290 :
291 1 : plugin->xml = load_glade_xml_file(main_window->location_list, filename);
292 :
293 1 : g_free(filename);
294 :
295 1 : if (plugin->xml == NULL)
296 0 : return FALSE;
297 : else
298 1 : return TRUE;
299 : }
300 :
301 : /**
302 : * To help plugins to deal with widgets, shows or hide a specific widget
303 : */
304 : void show_hide_widget(GtkWidget *widget, gboolean show, window_prop_t *win_prop)
305 0 : {
306 0 : if (win_prop != NULL)
307 : {
308 0 : if (show)
309 : {
310 0 : move_and_show_dialog_box(widget, win_prop);
311 : }
312 : else
313 : {
314 0 : record_and_hide_dialog_box(widget, win_prop);
315 : }
316 : }
317 : else
318 : {
319 0 : if (show)
320 : {
321 0 : gtk_widget_show(widget);
322 : }
323 : else
324 : {
325 0 : gtk_widget_hide(widget);
326 : }
327 : }
328 0 : }
329 :
330 :
331 : /**
332 : * To help the main program to send events to the plugins
333 : */
334 : void refresh_all_plugins(heraia_window_t *main_window)
335 1 : {
336 :
337 1 : GList *list = g_list_first(main_window->plugins_list);
338 1 : heraia_plugin_t *plugin = NULL;
339 :
340 3 : while (list != NULL)
341 : {
342 1 : plugin = (heraia_plugin_t *) list->data;
343 1 : if (plugin != NULL && plugin->refresh_proc != NULL)
344 1 : plugin->refresh_proc(main_window, list->data); /* Une petite astuce ! */
345 :
346 1 : list = list->next;
347 : }
348 1 : }
|