[Geany-Devel] New plugin loader mechanisms

Thomas Martitz kugel at xxxxx
Wed Mar 25 23:22:05 UTC 2015


Am 18.03.2015 um 22:55 schrieb Matthew Brush:
> On 15-03-18 09:42 AM, Thomas Martitz wrote:
>>
>> tl;dr <-
>> Key functions
>>
>> gboolean geany_load_module(GeanyPlugin *, GModule *)
>
> What is the GModule* for? Is it a .dll that Geany opened on behalf of 
> the plugin based on selection in Plugin Manager?

That's the function exported by native (C/C++) plugins that want to 
register as plugins with Geany. With my proposal that's the only 
function of a plugin that Geany gets through g_module_open(). Since this 
only applies to native shared libraries, the corresponding GModule is 
passed.

This function is similar to libpeas' peas_register_types().

>
>> gboolean geany_plugin_register(GeanyPlugin *, gint api, gint abi,
>> PluginHooks *(see below), gpointer)
>>
>> The plugin defines a single global function,
>> geany_load_module(GeanyPlugin *, GModule *). This is the only function
>> that geany learns about using g_module_symbol(). And the only thing this
>> function ought to do is to call geany_plugin_register(). This does 4 
>> things
>> 1) Provide the plugin handle to the plugin very early
>> 2) Perform abi and abi checks, so this is finally done inside geany.
>> Added bonus is that geany knows the requested api and can possibly apply
>> backcompat workarounds on a per plugin basis (instead of globally), warn
>> about very old plugins or even deny loading them.
>> 3) Register the remaining hooks and callbacks (see below)
>> 4) Associate a userdata pointer to the plugin, geany will pass this
>> pointer back to future calls into the plugin (good for proxies)
>>
>> In the future geany_plugin_register should be able to be used to
>> register plugins recursivly, by passing the appropriate GeanyPlugin
>> pointer, i.e. plugin A should be able to call
>> geany_plugin_register(plugin_B, ...) to realize pluxies.
>>
>> Now to the plugin hooks:
>> typedef struct _PluginHooks
>> {
>>      PluginCallback *callbacks;
>>      void        (*set_info)  (GeanyPlugin *plugin, gpointer pdata);
>>      void        (*init)      (GeanyPlugin *plugin, gpointer pdata);
>>      GtkWidget*  (*configure) (GeanyPlugin *plugin, GtkDialog *dialog,
>> gpointer pdata);
>>      void        (*help)      (GeanyPlugin *plugin, gpointer pdata);
>>      void        (*cleanup)   (GeanyPlugin *plugin, gpointer pdata);
>> }
>> PluginHooks;
>>
>
> What if instead of PluginHooks it was called `Plugin` (GeanyPlugin is 
> taken, so for this discussion I'll use `Plugin` :) and instead of just 
> the callback function pointers it contained the (possibly 
> sub-)plugin's info, like this:

Plugin is also taken inside Geany :)


>
> ```
> typedef struct
> {
>   const char *name;
>   const char *version;
>   const char *author;
>   const char *description;
>   unsigned    api_min;
>   unsigned    abi_ver;
>   void       *plugin_data; // pdata/plugin context
>
>   bool      (*init) (Plugin*);
>   GtkWidget (*configure) (Plugin,GtkDialog*);
>   gchar*    (*help) (Plugin*); // if not NULL ret, show URL in browser
>   bool      (*deinit) (Plugin*); // could signal unloading problem
> }
> Plugin;
> ```
>
> Then the "register" function could be like:
>
> ```
> bool plugin_register (GeanyPlugin *module, // geany's plugin context
>                       Plugin      *plugin); // real/sub-plugin ctx
> ```
>
> Inside a normal plugin it could do:
>
> ```
> static Plugin my_plugin = {
>   .name        = "Foo",
>   .version     = "0.1",
>   .author      = "Me",
>   .description = "Foo plugin",
>   .api_min     = 200,
>   .abi_ver     = GEANY_ABI_VERSION,
>   .init        = my_plugin_init,
>   .configure   = my_plugin_configure,
>   .help        = my_plugin_help,
>   .deinit      = my_plugin_cleanup,
> };
>
> G_MODULE_EXPORT
> bool plugin_load_module (GeanyPlugin *module_plugin)
> {
>   return plugin_register (module_plugin, &my_plugin);
> }
> ```
>
> Or for a proxying-type plugin (ex. GeanyPy/GeanyLua):
>
> ```
> G_MODULE_EXPORT
> bool plugin_load_module (GeanyPlugin *module_plugin)
> {
>   Plugin *plug = g_new0 (Plugin, 1);
>   *plug = my_plugin;
>   plug->name = "Joe's plugin";
>   plug->version = etc...
>   plug->plugin_data = PyObject_New(...); // or lua_new() or whatever
>   return plugin_register (module_plugin, plug);
> }
> ```
>
> Just some ideas based on yours and mine previous work around this. 
> There's many ways to skin this cat :)

That's only a slightly different version of my proposal, it's 
fundamentally the same. Glad you like it :D

Thanks for your suggestion to make the plugin_set_info() obsolete and 
move filing the info fields before geany_plugin_register(). I will 
incoperate that into my v2 of my proposal.

Best regards


More information about the Devel mailing list