plugin.c

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /*
00003  *  plugin.c
00004  *  heraia - an hexadecimal file editor and analyser based on ghex
00005  *
00006  *  (C) Copyright 2007 - 2010 Olivier Delhomme
00007  *  e-mail : heraia@delhomme.org
00008  *  URL    : http://heraia.tuxfamily.org
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2, or  (at your option)
00013  *  any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY;  without even the implied warranty of
00017  *  MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024 /**
00025  * @file plugin.c
00026  * This file contains all the stuff that is dedicated to plugins (loading,
00027  * instanciating, initializing and so on)
00028  */
00029 #include <libheraia.h>
00030 
00031 static heraia_plugin_t *get_plugin_handle(heraia_struct_t *main_struct, heraia_plugin_t *plugin,
00032                                           const gchar *full_filename, const gchar *filename);
00033 static heraia_plugin_t *get_plugin_init_symbol(heraia_struct_t *main_struct, heraia_plugin_t *plugin);
00034 static void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb);
00035 static void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb);
00036 
00037 
00038 /**
00039  * @fn gboolean plugin_capable(void)
00040  * Says whether the system can handle plugins (or not)
00041  * @return Returns TRUE if the system is able to handle plugins, FALSE otherwise
00042  */
00043 gboolean plugin_capable(void)
00044 {
00045     return g_module_supported();
00046 }
00047 
00048 
00049 /**
00050  * @fn new_plugin(void)
00051  *  Creates a new empty plugin
00052  *  it may be initialised by
00053  *  the plugin itself !
00054  * @return Returns a newly created heraia_plugin_t plugin structure
00055  */
00056 heraia_plugin_t *new_plugin(void)
00057 {
00058     heraia_plugin_t *new = NULL;
00059 
00060     new = (heraia_plugin_t *) g_malloc0(sizeof(heraia_plugin_t));
00061 
00062     new->state = PLUGIN_STATE_NEW; /* The plugin state         */
00063     new->handle = NULL;            /* The module handle        */
00064     new->path = NULL;              /* The path to the plugin   */
00065     new->filename = NULL;
00066     new->info = (plugin_info_t *) g_malloc0(sizeof(plugin_info_t));       /* The plugin information   */
00067     new->filter = (plugin_filter_t *) g_malloc0(sizeof(plugin_filter_t)); /* The plugin filter        */
00068     new->error = NULL;
00069     new->extra = NULL;      /* Plugin-specific data     */
00070 
00071     /* Called when the application initialy starts up */
00072     new->init_proc = NULL;
00073     /* Called when the application exits */
00074     new->quit_proc = NULL;
00075     /* Called to run a miscellaneous thing everytime the plugin is called */
00076     new->run_proc = NULL;
00077 
00078     return new;
00079 
00080 }
00081 
00082 
00083 /**
00084  * @fn free_plugin(heraia_plugin_t *plugin)
00085  *  free an unused plugin use with caution
00086  * @param plugin : A created a malloc'ed plugin
00087  */
00088 void free_plugin(heraia_plugin_t *plugin)
00089 {
00090     if (plugin != NULL)
00091         {
00092             if (plugin->handle != NULL)
00093                 {
00094                     g_module_close(plugin->handle);
00095                 }
00096 
00097             if (plugin->info != NULL)
00098                 {
00099                     g_free(plugin->info->name);
00100                     g_free(plugin->info->version);
00101                     g_free(plugin->info->summary);
00102                     g_free(plugin->info->description);
00103                     g_free(plugin->info->author);
00104                     g_free(plugin->info->homepage);
00105                     g_free(plugin->info);
00106                 }
00107 
00108             if (plugin->filter != NULL)
00109                 {
00110                     g_free(plugin->filter->extensions);
00111                     g_free(plugin->filter);
00112                 }
00113 
00114             g_free(plugin->path);
00115             g_free(plugin->filename);
00116             g_free(plugin->error);
00117             g_free(plugin->extra);
00118 
00119             g_free(plugin);
00120         }
00121 }
00122 
00123 
00124 /**
00125  * @fn heraia_plugin_t *get_plugin_handle(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *full_filename, const gchar *filename)
00126  *  Here we try to get a handle for the Gmodule referenced by full_filename
00127  * @param main_struct : main structure
00128  * @param plugin : the plugin we try to get a handle for
00129  * @param full_filename : the full filename (includes path) to the compiled
00130  *                        plugin
00131  * @param filename : the filename (without the path -> used for fancy log
00132  *                                 reporting)
00133  * @return Returns the modified plugin structure eventually with a handle !
00134  */
00135 static heraia_plugin_t *get_plugin_handle(heraia_struct_t *main_struct, heraia_plugin_t *plugin,
00136                                           const gchar *full_filename, const gchar *filename)
00137 {
00138     if (plugin != NULL)
00139         {
00140 
00141             plugin->handle = g_module_open(full_filename, G_MODULE_BIND_MASK);
00142 
00143             if (plugin->handle == NULL)
00144                 {
00145                     log_message(main_struct, G_LOG_LEVEL_WARNING, Q_("Could not open plugin %s - %s"), filename, g_module_error());
00146                 }
00147         }
00148 
00149     return plugin;
00150 }
00151 
00152 
00153 /**
00154  * @fn heraia_plugin_t *get_plugin_init_symbol(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00155  *  If the handle is ok, we want to have the heraia_plugin_init function (to call it)
00156  *  in order to init the plugin (by itself)
00157  * @param main_struct : main structure
00158  * @param plugin : the plugin to look for its init function
00159  */
00160 static heraia_plugin_t *get_plugin_init_symbol(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00161 {
00162     heraia_plugin_t *(*heraia_plugin_init)(heraia_plugin_t *);
00163     gboolean get_symbol = FALSE;
00164 
00165     if (plugin != NULL && plugin->handle != NULL)
00166         {
00167             get_symbol = g_module_symbol(plugin->handle, "heraia_plugin_init", (gpointer *)(&heraia_plugin_init));
00168 
00169             if (get_symbol == FALSE)
00170                 {
00171                     log_message(main_struct, G_LOG_LEVEL_WARNING, "%s", g_module_error());
00172                     free_plugin(plugin);
00173                     return NULL;
00174                 }
00175             else
00176                 {
00177                     /* the plugins inits itself here */
00178                     plugin = heraia_plugin_init(plugin);
00179                     return plugin;
00180                 }
00181         }
00182     else
00183         {
00184             free_plugin(plugin);
00185             return NULL;
00186         }
00187 }
00188 
00189 
00190 /**
00191  * @fn void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
00192  *  finalising initialisation : if everything went fine, the plugin is added to the
00193  *  plugin list and a menu entry is created in the Plugins menu
00194  * @param main_struct : main structure
00195  * @param plugin : the plugin that was initialized
00196  * @param filename : filename of the plugin itself
00197  * @param plugins_nb : a number that will become the id of that plugin
00198  */
00199 static void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
00200 {
00201     if (plugin != NULL)
00202         {
00203             plugin->info->id = plugins_nb;
00204             main_struct->plugins_list = g_list_append(main_struct->plugins_list, plugin);
00205             log_message(main_struct, G_LOG_LEVEL_INFO, Q_("plugin %s loaded."), filename);
00206 
00207             plugin->init_proc(main_struct);
00208 
00209             if (plugin->info->type == HERAIA_PLUGIN_ACTION)
00210                 {
00211                     add_entry_to_plugins_menu(main_struct, plugin);
00212                 }
00213 
00214         }
00215  }
00216 
00217 
00218 /**
00219  * @fn void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb)
00220  *  Here we manage to load one plugin at a time (and this is really enough !)
00221  * @param main_struct : main structure
00222  * @param filename : filename of the plugin that we want to load
00223  * @param plugins_nb : a number that will be the id of that plugin
00224  */
00225 static void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb)
00226 {
00227     const gchar *full_filename = NULL;
00228     heraia_plugin_t *plugin = NULL;
00229     gchar *ext = g_strdup_printf(".%s", G_MODULE_SUFFIX); /* system dependent suffix */
00230 
00231     full_filename = g_build_filename(PLUGINS_DIR, filename, NULL);
00232 
00233     /* Make sure we do load the module named .so, .dll or .sl depending on the OS type */
00234     if ( (g_file_test(full_filename, G_FILE_TEST_IS_DIR) == FALSE) &&
00235          (strcmp(strrchr(filename, '.'), ext) == 0)
00236          )
00237         {
00238             plugin = new_plugin();
00239             plugin->path = g_strdup_printf("%s", PLUGINS_DIR);
00240             plugin->filename = g_strdup_printf("%s", filename);
00241 
00242             plugin = get_plugin_handle(main_struct, plugin, full_filename, filename);
00243             plugin = get_plugin_init_symbol(main_struct, plugin);
00244 
00245             init_plugin(main_struct, plugin, filename, plugins_nb);
00246         }
00247 }
00248 
00249 
00250 /**
00251  * @fn load_plugins(heraia_struct_t *main_struct)
00252  *  looks at the plugins dir(s) and loads
00253  *  the needed plugins (all ;-) (one at a time !!)
00254  * @param main_struct : main structure
00255  */
00256 void load_plugins(heraia_struct_t *main_struct)
00257 {
00258     GDir *plugins_dir = NULL;
00259     GError *error = NULL;
00260     const gchar *filename = NULL;
00261     unsigned int plugins_nb = 0;
00262 
00263     /* Register all shared plugins (plugins_dir) (-DPLUGINS_DIR) */
00264     /* This may be a config file option later ...                */
00265     plugins_dir = g_dir_open(PLUGINS_DIR, 0, &error);
00266 
00267     if (plugins_dir == NULL) /* error while openning the plugins directory */
00268         {
00269             log_message(main_struct, G_LOG_LEVEL_WARNING, "%s", error->message);
00270             g_error_free(error);
00271         }
00272     else
00273         {
00274             while ((filename = g_dir_read_name(plugins_dir)) != NULL)
00275                 {
00276                     if (g_str_has_suffix(filename, "libheraia.so") == FALSE)
00277                     {
00278                         load_one_plugin(main_struct, filename, ++plugins_nb);
00279                     }
00280                 }
00281             g_dir_close(plugins_dir);
00282         }
00283 }
00284 
00285 
00286 /**
00287  * @fn add_entry_to_plugins_menu(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00288  *  adds a menu entry to the plugin menu
00289  *  adds a signal handler when the menu is toggled
00290  * @param main_struct : main structure
00291  * @param plugin : a plugin to add to the plugin's menu
00292  */
00293 void add_entry_to_plugins_menu(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00294 {
00295     if (plugin != NULL && plugin->info != NULL && plugin->info->name != NULL)
00296         {
00297             /* Creates the menu entry (a GtkCheckMenuItem) */
00298             plugin->cmi_entry = GTK_CHECK_MENU_ITEM(gtk_check_menu_item_new_with_label(plugin->info->name));
00299 
00300             /* Append this menu entry to the menu */
00301             gtk_menu_shell_append(GTK_MENU_SHELL(heraia_get_widget(main_struct->xmls->main, "plugins_menu")), GTK_WIDGET(plugin->cmi_entry));
00302 
00303             /* Connect the menu entry toggled signal to the run_proc function of the plugin */
00304             g_signal_connect(G_OBJECT(plugin->cmi_entry), "toggled", G_CALLBACK(plugin->run_proc), main_struct);
00305 
00306             /* Shows the menu entry (so we may toggle it!) */
00307             gtk_widget_show(GTK_WIDGET(plugin->cmi_entry));
00308         }
00309 }
00310 
00311 
00312 /**
00313  * @fn heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
00314  *  Finds the desired plugin by its name and return the plugin structure or NULL
00315  * @param plugins_list : list of all available plugins
00316  * @param name : plugin's name we're looking for
00317  * @return Returns a heraia_plugin_t that correspond to the plugin or NULL if
00318  *         no plugin was found with that name
00319  */
00320 heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
00321 {
00322     GList *list = g_list_first(plugins_list);
00323     heraia_plugin_t *plugin = NULL;
00324     gboolean stop = FALSE;
00325 
00326     while (list != NULL && stop != TRUE)
00327         {
00328             plugin = (heraia_plugin_t *) list->data;
00329             if (plugin != NULL && plugin->info != NULL)
00330                 {
00331                     if (strcmp(plugin->info->name, name) == 0)
00332                         stop = TRUE;
00333                 }
00334             list = list->next;
00335         }
00336 
00337     if (stop == TRUE)
00338         return plugin;
00339     else
00340         return NULL;
00341 }
00342 
00343 
00344 /**
00345  * @fn load_plugin_xml(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00346  *  Loads the xml's definition file that describes the plugin (.gtkbuilder suffix)
00347  *  tries the paths found in the location_list
00348  * @param main_struct : main structure
00349  * @param plugin : plugin for whom we want to load it's GtkBuilder XML definition
00350  *        file
00351  * @return Returns TRUE if everything went ok, FALSE otherwise
00352  */
00353 gboolean load_plugin_xml(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00354 {
00355     gchar *filename = NULL;
00356 
00357     filename = g_strdup_printf("%s.gtkbuilder", plugin->info->name);
00358 
00359     plugin->xml = load_xml_file(main_struct->location_list, filename);
00360 
00361     g_free(filename);
00362 
00363     if (plugin->xml == NULL)
00364         return FALSE;
00365     else
00366         return TRUE;
00367 }
00368 
00369 
00370 /**
00371  * @fn refresh_all_plugins(heraia_struct_t *main_struct)
00372  *  To help the main program to send events to the plugins
00373  * @param main_struct : main structure
00374  */
00375 void refresh_all_plugins(heraia_struct_t *main_struct)
00376 {
00377 
00378     GList *list = g_list_first(main_struct->plugins_list);
00379     heraia_plugin_t *plugin = NULL;
00380 
00381     while (list != NULL)
00382         {
00383             plugin = (heraia_plugin_t *) list->data;
00384 
00385             if (plugin != NULL && plugin->refresh_proc != NULL)
00386                 { /* Beware : here a tricky thing that works ! */
00387                     plugin->refresh_proc(main_struct, list->data);
00388                 }
00389 
00390             list = list->next;
00391         }
00392 }
Generated on Tue Aug 10 18:29:02 2010 for Heraia by  doxygen 1.6.3