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 - 2009 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_window_t *main_window, heraia_plugin_t *plugin, 
00032                                                                                   const gchar *full_filename, const gchar *filename);
00033 static heraia_plugin_t *get_plugin_init_symbol(heraia_window_t *main_window, heraia_plugin_t *plugin);
00034 static void init_plugin(heraia_window_t *main_window, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb);
00035 static void load_one_plugin(heraia_window_t *main_window, const gchar *filename, guint plugins_nb);
00036 
00037 /**
00038  * @fn gboolean plugin_capable(void)
00039  * Says whether the system can handle plugins (or not)
00040  * @return Returns TRUE if the system is able to handle plugins, FALSE otherwise
00041  */
00042 gboolean plugin_capable(void)
00043 {
00044         return g_module_supported();
00045 }
00046 
00047 /**  
00048  * @fn new_plugin(void)
00049  *  Creates a new empty plugin 
00050  *  it may be initialised by
00051  *  the plugin itself !
00052  * @return Returns a newly created heraia_plugin_t plugin structure
00053  */
00054 heraia_plugin_t *new_plugin(void)
00055 {
00056         heraia_plugin_t *new = NULL;
00057         
00058         new = (heraia_plugin_t *) g_malloc0(sizeof(heraia_plugin_t));
00059 
00060         new->state = PLUGIN_STATE_NEW; /* The plugin state         */
00061         new->handle = NULL;            /* The module handle        */
00062         new->path = NULL;              /* The path to the plugin   */
00063         new->filename = NULL;
00064         new->info = (plugin_info_t *) g_malloc0(sizeof(plugin_info_t));       /* The plugin information   */
00065         new->filter = (plugin_filter_t *) g_malloc0(sizeof(plugin_filter_t)); /* The plugin filter        */
00066         new->error = NULL;
00067         new->extra = NULL;      /* Plugin-specific data     */
00068 
00069         /* Called when the application initialy starts up */
00070         new->init_proc = NULL;
00071         /* Called when the application exits */
00072         new->quit_proc = NULL;
00073         /* Called to run a miscellaneous thing everytime the plugin is called */
00074         new->run_proc = NULL;
00075 
00076         return new;
00077 
00078 }
00079 
00080 /**
00081  * @fn free_plugin(heraia_plugin_t *plugin)
00082  *  free an unused plugin use with caution
00083  * @param plugin : A created a malloc'ed plugin 
00084  */
00085 void free_plugin(heraia_plugin_t *plugin)
00086 {
00087         if (plugin != NULL)
00088                 {
00089                         if (plugin->handle != NULL)
00090                                 g_module_close(plugin->handle);
00091                         if (plugin->info != NULL)
00092                                 {
00093                                         g_free(plugin->info->name);
00094                                         g_free(plugin->info->version);
00095                                         g_free(plugin->info->summary);
00096                                         g_free(plugin->info->description);
00097                                         g_free(plugin->info->author);
00098                                         g_free(plugin->info->homepage);
00099                                         g_free(plugin->info);
00100                                 }
00101                         if (plugin->filter != NULL)
00102                                 {
00103                                         g_free(plugin->filter->extensions);
00104                                         g_free(plugin->filter);
00105                                 }
00106                         g_free(plugin->path);
00107                         g_free(plugin->filename);
00108                         g_free(plugin->error);
00109                         g_free(plugin->extra);
00110                         
00111                         g_free(plugin);
00112                 }
00113 }
00114 
00115 /**
00116  * @fn heraia_plugin_t *get_plugin_handle(heraia_window_t *main_window, heraia_plugin_t *plugin, const gchar *full_filename, const gchar *filename)
00117  *  Here we try to get a handle for the Gmodule referenced by full_filename
00118  * @param main_window : main structure
00119  * @param plugin : the plugin we try to get a handle for
00120  * @param full_filename : the full filename (includes path) to the compiled 
00121  *                            plugin
00122  * @param filename : the filename (without the path -> used for fancy log 
00123  *                                                                 reporting) 
00124  * @return Returns the modified plugin structure eventually with a handle !
00125  */
00126 static heraia_plugin_t *get_plugin_handle(heraia_window_t *main_window, heraia_plugin_t *plugin, 
00127                                                                                   const gchar *full_filename, const gchar *filename)
00128 {
00129         if (plugin != NULL)
00130                 {
00131 
00132                         plugin->handle = g_module_open(full_filename, G_MODULE_BIND_MASK);
00133                         
00134                         if (plugin->handle == NULL)
00135                                 {
00136                                         log_message(main_window, G_LOG_LEVEL_WARNING, "Could not open plugin %s - %s", filename, g_module_error());
00137                                 }
00138                 }
00139 
00140         return plugin;
00141 }
00142 
00143 /**
00144  * @fn heraia_plugin_t *get_plugin_init_symbol(heraia_window_t *main_window, heraia_plugin_t *plugin)
00145  *  If the handle is ok, we want to have the heraia_plugin_init function (to call it)
00146  *  in order to init the plugin (by itself)
00147  * @param main_window : main structure
00148  * @param plugin : the plugin to look for its init function
00149  */ 
00150 static heraia_plugin_t *get_plugin_init_symbol(heraia_window_t *main_window, heraia_plugin_t *plugin)
00151 {
00152         heraia_plugin_t *(*heraia_plugin_init)(heraia_plugin_t *);
00153         gboolean get_symbol = FALSE;
00154 
00155         if (plugin != NULL && plugin->handle != NULL)
00156                 {
00157                         get_symbol = g_module_symbol(plugin->handle, "heraia_plugin_init", (gpointer *)(&heraia_plugin_init));
00158 
00159                         if (get_symbol == FALSE)
00160                                 {
00161                                         log_message(main_window, G_LOG_LEVEL_WARNING, "%s", g_module_error());
00162                                         free_plugin(plugin);
00163                                         return NULL;
00164                                 }
00165                         else
00166                                 {
00167                                         /* the plugins inits itself here */
00168                                         plugin = heraia_plugin_init(plugin);
00169                                         return plugin;
00170                                 }
00171                 }
00172         else
00173                 {
00174                         free_plugin(plugin);
00175                         return NULL;
00176                 }
00177 }
00178 
00179 /**
00180  * @fn void init_plugin(heraia_window_t *main_window, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
00181  *  finalising initialisation : if everything went fine, the plugin is added to the 
00182  *  plugin list and a menu entry is created in the Plugins menu
00183  * @param main_window : main structure
00184  * @param plugin : the plugin that was initialized
00185  * @param filename : filename of the plugin itself
00186  * @param plugins_nb : a number that will become the id of that plugin
00187  */
00188 static void init_plugin(heraia_window_t *main_window, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
00189 {       
00190         if (plugin != NULL)
00191                 {
00192                         plugin->info->id = plugins_nb;
00193                         main_window->plugins_list = g_list_append(main_window->plugins_list, plugin);
00194                         log_message(main_window, G_LOG_LEVEL_INFO, "plugin %s loaded.", filename);
00195                         plugin->init_proc(main_window);
00196                         if (plugin->info->type == HERAIA_PLUGIN_ACTION)
00197                                 {
00198                                         add_entry_to_plugins_menu(main_window, plugin);
00199                                 }
00200                                 
00201                 }
00202  }
00203 
00204 /**
00205  * @fn void load_one_plugin(heraia_window_t *main_window, const gchar *filename, guint plugins_nb)
00206  *  Here we manage to load one plugin at a time (and this is really enough !)
00207  * @param main_window : main structure 
00208  * @param filename : filename of the plugin that we want to load
00209  * @param plugins_nb : a number that will be the id of that plugin
00210  */
00211 static void load_one_plugin(heraia_window_t *main_window, const gchar *filename, guint plugins_nb)
00212 {
00213         const gchar *full_filename = NULL;
00214         heraia_plugin_t *plugin = NULL;
00215         gchar *ext = g_strdup_printf(".%s", G_MODULE_SUFFIX); /* system dependent suffix */
00216 
00217         full_filename = g_build_filename(PLUGINS_DIR, filename, NULL);
00218 
00219         /* Make sure we do load the module named .so, .dll or .sl depending on the OS type */
00220         if ( (g_file_test(full_filename, G_FILE_TEST_IS_DIR) == FALSE) &&
00221                  (strcmp(strrchr(filename, '.'), ext) == 0)
00222                  )
00223                 {
00224                         plugin = new_plugin();
00225                         plugin->path = g_strdup_printf("%s", PLUGINS_DIR);
00226                         plugin->filename = g_strdup_printf("%s", filename);
00227                                                         
00228                         plugin = get_plugin_handle(main_window, plugin, full_filename, filename);
00229                         plugin = get_plugin_init_symbol(main_window, plugin);
00230                    
00231                         init_plugin(main_window, plugin, filename, plugins_nb);
00232                 }
00233 }
00234 
00235 
00236 /**
00237  * @fn load_plugins(heraia_window_t *main_window)
00238  *  looks at the plugins dir(s) and loads
00239  *  the needed plugins (all ;-) (one at a time !!)
00240  * @param main_window : main structure
00241  */
00242 void load_plugins(heraia_window_t *main_window)
00243 {
00244         GDir *plugins_dir = NULL;
00245         GError *error = NULL;
00246         const gchar *filename = NULL;
00247         unsigned int plugins_nb = 0;
00248 
00249         /* Register all shared plugins (plugins_dir) (-DPLUGINS_DIR) */
00250     /* This may be a config file option later ...                */
00251         plugins_dir = g_dir_open(PLUGINS_DIR, 0, &error);
00252 
00253         if (plugins_dir == NULL) /* error while openning the plugins directory */
00254                 {  
00255                         log_message(main_window, G_LOG_LEVEL_WARNING, "%s", error->message);
00256                         g_error_free(error);
00257                 }
00258         else
00259                 {
00260                         while ((filename = g_dir_read_name(plugins_dir)) != NULL) 
00261                                 {
00262                                         load_one_plugin(main_window, filename, ++plugins_nb);
00263                                 }
00264                         g_dir_close(plugins_dir);
00265                 }
00266 }
00267 
00268 /**
00269  * @fn add_entry_to_plugins_menu(heraia_window_t *main_window, heraia_plugin_t *plugin)
00270  *  adds a menu entry to the plugin menu
00271  *  adds a signal handler when the menu is toggled
00272  * @param main_window : main structure
00273  * @param plugin : a plugin to add to the plugin's menu 
00274  */
00275 void add_entry_to_plugins_menu(heraia_window_t *main_window, heraia_plugin_t *plugin)
00276 {
00277         if (plugin != NULL && plugin->info != NULL && plugin->info->name != NULL)
00278         {
00279                 /* Creates the menu entry (a GtkCheckMenuItem) */
00280                 plugin->cmi_entry = GTK_CHECK_MENU_ITEM(gtk_check_menu_item_new_with_label(plugin->info->name));
00281 
00282                 /* Append this menu entry to the menu */
00283                 gtk_menu_shell_append(GTK_MENU_SHELL(heraia_get_widget(main_window->xmls->main, "plugins_menu")), GTK_WIDGET(plugin->cmi_entry));
00284 
00285                 /* Connect the menu entry toggled signal to the run_proc function of the plugin */
00286                 g_signal_connect(G_OBJECT(plugin->cmi_entry), "toggled", G_CALLBACK(plugin->run_proc), main_window);
00287 
00288                 /* Shows the menu entry (so we may toggle it!) */
00289                 gtk_widget_show(GTK_WIDGET(plugin->cmi_entry));
00290         }
00291 }
00292 
00293 /**
00294  * @fn heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
00295  *  Finds the desired plugin by its name and return the plugin structure or NULL
00296  * @param plugins_list : list of all available plugins
00297  * @param name : plugin's name we're looking for
00298  * @return Returns a heraia_plugin_t that correspond to the plugin or NULL if
00299  *         no plugin was found with that name
00300  */
00301 heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
00302 {
00303         GList *list = g_list_first(plugins_list);
00304         heraia_plugin_t *plugin = NULL;
00305         gboolean stop = FALSE;
00306 
00307         while (list != NULL && stop != TRUE)
00308                 {
00309                         plugin = (heraia_plugin_t *) list->data;
00310                         if (plugin != NULL && plugin->info != NULL)
00311                                 {
00312                                         if (strcmp(plugin->info->name, name) == 0)
00313                                                 stop = TRUE;
00314                                 }
00315                         list = list->next;
00316                 }
00317         
00318         if (stop == TRUE)
00319                 return plugin;
00320         else
00321                 return NULL;
00322 }
00323 
00324 
00325 /** 
00326  * @fn load_plugin_glade_xml(heraia_window_t *main_window, heraia_plugin_t *plugin)
00327  *  Loads the glade xml file that describes the plugin (.glade suffix)
00328  *  tries the paths found in the location_list
00329  * @param main_window : main structure
00330  * @param plugin : plugin for whom we want to load it's glade XML definition 
00331  *        file
00332  * @return Returns TRUE if everything went ok, FALSE otherwise
00333  */
00334 gboolean load_plugin_glade_xml(heraia_window_t *main_window, heraia_plugin_t *plugin)
00335 {       
00336         gchar *filename = NULL;
00337 
00338         filename = g_strdup_printf("%s.glade", plugin->info->name);     
00339       
00340         plugin->xml = load_glade_xml_file(main_window->location_list, filename);
00341 
00342         g_free(filename);
00343         
00344         if (plugin->xml == NULL)
00345                 return FALSE;
00346         else
00347                 return TRUE;
00348 }
00349 
00350 /**
00351  * @fn show_hide_widget(GtkWidget *widget, gboolean show, window_prop_t *win_prop)
00352  *  To help plugins to deal with widgets, shows or hide a specific widget
00353  * @param widget : the widget to show or hide
00354  * @param show : what to do : TRUE to show the widget, FALSE to hide it
00355  * @param win_prop : window properties.
00356  * @todo should this function go to heraia_ui.c instead of here ?
00357  */
00358 void show_hide_widget(GtkWidget *widget, gboolean show, window_prop_t *win_prop)
00359 {
00360         if (win_prop != NULL)
00361         {
00362                 if (show)
00363                 {
00364                         move_and_show_dialog_box(widget, win_prop);
00365                 }
00366                 else
00367                 {
00368                         record_and_hide_dialog_box(widget, win_prop);
00369                 }
00370         }
00371         else
00372         {
00373                 if (show)
00374                 {
00375                         gtk_widget_show(widget);
00376                 }
00377                 else
00378                 {
00379                         gtk_widget_hide(widget);
00380                 }
00381         }
00382 }
00383 
00384 
00385 /**
00386  * @fn refresh_all_plugins(heraia_window_t *main_window)
00387  *  To help the main program to send events to the plugins
00388  * @param main_window : main structure
00389  */
00390 void refresh_all_plugins(heraia_window_t *main_window)
00391 {
00392         
00393         GList *list = g_list_first(main_window->plugins_list);
00394         heraia_plugin_t *plugin = NULL;
00395 
00396         while (list != NULL)
00397                 {
00398                         plugin = (heraia_plugin_t *) list->data;
00399                         if (plugin != NULL && plugin->refresh_proc != NULL)
00400                         { /* Beware : here a tricky thing that works ! */
00401                                 plugin->refresh_proc(main_window, list->data);  
00402                         }
00403                                 
00404                         list = list->next;
00405                 }
00406 }

Generated on Sat Mar 14 13:44:29 2009 for Heraia by  doxygen 1.5.6