Move plugin name and description into a separate struct, which is set

by calling the PLUGIN_INFO() macro - this can be read before the
plugin is initialized.
Added more comments for plugin authors.


git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@1645 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
Nick Treleaven 2007-06-27 15:56:42 +00:00
parent fcb06167b4
commit a549a99c33
4 changed files with 76 additions and 21 deletions

View File

@ -1,3 +1,12 @@
2007-06-27 Nick Treleaven <nick.treleaven@btinternet.com>
* plugins/demoplugin.c, src/plugindata.h, src/plugins.c:
Move plugin name and description into a separate struct, which is set
by calling the PLUGIN_INFO() macro - this can be read before the
plugin is initialized.
Added more comments for plugin authors.
2007-06-26 Nick Treleaven <nick.treleaven@btinternet.com>
* plugins/demoplugin.c, plugins/Makefile.am, configure.in,

View File

@ -38,12 +38,15 @@ static struct
local_data;
/* This performs runtime checks that try to ensure:
* 1. Geany ABI data types are compatible with this plugin.
* 2. Geany sources provide the required API for this plugin. */
VERSION_CHECK(1)
/* Check that Geany supports plugin API version 2 or later, and check
* for binary compatibility. */
VERSION_CHECK(2)
/* All plugins must set name and description */
PLUGIN_INFO(_("Demo"), _("Example plugin."))
/* Callback when the menu item is clicked */
static void
item_activate(GtkMenuItem *menuitem, gpointer gdata)
{
@ -56,28 +59,35 @@ item_activate(GtkMenuItem *menuitem, gpointer gdata)
GTK_BUTTONS_OK,
_("Hello World!"));
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
_("(From the %s plugin)"), my_data->name);
_("(From the %s plugin)"), info()->name);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
/* Called by Geany to initialize the plugin */
void init(PluginData *data)
{
my_data = data;
my_data->name = g_strdup("Demo");
GtkWidget *demo_item;
local_data.menu_item = gtk_menu_item_new_with_mnemonic(_("_Demo Plugin"));
gtk_widget_show(local_data.menu_item);
gtk_container_add(GTK_CONTAINER(my_data->tools_menu), local_data.menu_item);
g_signal_connect(G_OBJECT(local_data.menu_item), "activate", G_CALLBACK(item_activate), NULL);
my_data = data; // keep a pointer to the main application fields & functions
// Add an item to the Tools menu
demo_item = gtk_menu_item_new_with_mnemonic(_("_Demo Plugin"));
gtk_widget_show(demo_item);
gtk_container_add(GTK_CONTAINER(my_data->tools_menu), demo_item);
g_signal_connect(G_OBJECT(demo_item), "activate", G_CALLBACK(item_activate), NULL);
// keep a pointer to the menu item, so we can remove it when the plugin is unloaded
local_data.menu_item = demo_item;
}
/* Called by Geany before unloading the plugin.
* Here any UI changes should be removed, memory freed and any other finalization done */
void cleanup()
{
// remove the menu item added in init()
gtk_widget_destroy(local_data.menu_item);
g_free(my_data->name);
}

View File

@ -27,14 +27,16 @@
/* The API version should be incremented whenever any plugin data types below are
* modified. */
static const gint api_version = 1;
static const gint api_version = 2;
/* The ABI version should be incremented whenever existing fields in the plugin
* data types below have to be changed or reordered. It should stay the same if fields
* are only appended, as this doesn't affect existing fields. */
static const gint abi_version = 1;
static const gint abi_version = 2;
/* This performs runtime checks that try to ensure:
* 1. Geany ABI data types are compatible with this plugin.
* 2. Geany sources provide the required API for this plugin. */
/* TODO: if possible, the API version should be checked at compile time, not runtime. */
#define VERSION_CHECK(api_required) \
gint version_check(gint abi_ver) \
@ -47,18 +49,37 @@ static const gint abi_version = 1;
}
typedef struct PluginData PluginData;
struct PluginData
typedef struct PluginInfo
{
gchar *name; // name of plugin
gchar *description; // description of plugin
}
PluginInfo;
/* Sets the plugin name and a brief description of what it is. */
#define PLUGIN_INFO(p_name, p_description) \
PluginInfo *info() \
{ \
static PluginInfo p_info; \
\
p_info.name = (p_name); \
p_info.description = (p_description); \
return &p_info; \
}
/* These are fields and functions owned by Geany.
* Fields will be appended when needed by plugin authors.
* Note: Remember to increment api_version (and abi_version if necessary) when
* making changes. */
typedef struct PluginData
{
MyApp *app; // Geany application data fields
/* Almost all plugins should add menu items to the Tools menu only */
GtkWidget *tools_menu;
};
}
PluginData;
#endif

View File

@ -42,6 +42,7 @@ struct Plugin
gchar *filename; // plugin filename (/path/libname.so)
PluginData data;
PluginInfo* (*info) (); /* Returns plugin name, description */
void (*init) (PluginData *data); /* Called when the plugin is enabled */
void (*cleanup) (); /* Called when the plugin is disabled or when Geany exits */
};
@ -102,6 +103,7 @@ plugin_new(const gchar *fname)
{
Plugin *plugin;
GModule *module;
PluginInfo* (*info)();
g_return_val_if_fail(fname, NULL);
g_return_val_if_fail(g_module_supported(), NULL);
@ -129,7 +131,20 @@ plugin_new(const gchar *fname)
return NULL;
}
g_module_symbol(module, "info", (void *) &info);
if (info == NULL)
{
geany_debug("Unknown plugin info for \"%s\"!", fname);
if (! g_module_close(module))
g_warning("%s: %s", fname, g_module_error());
return NULL;
}
geany_debug("Initializing plugin '%s' (%s)",
info()->name, info()->description);
plugin = g_new0(Plugin, 1);
plugin->info = info;
plugin->filename = g_strdup(fname);
plugin->module = module;
@ -143,7 +158,7 @@ plugin_new(const gchar *fname)
plugin->init(&plugin->data);
geany_debug("Loaded: %s (%s)", fname,
NVL(plugin->data.name, "<Unknown>"));
NVL(plugin->info()->name, "<Unknown>"));
return plugin;
}