[Geany-Devel] RFC: Proxy plugins
Thomas Martitz
kugel at xxxxx
Wed May 7 06:40:13 UTC 2014
Hello,
I'm (as of now) motivated to implement proxy plugins (to my amusement,
until splitwindow2 gets finally reviewed...). Therefore I would like to
receive comments on my proposed concept and APIs (further below).
I would also love to discuss about better terms for proxy and "the
proxied plugins". I think some adorable internal code/nick names could
help us to not get confused in this business.
Note that I have implemented very little yet, so there might be unknown
roadblocks and things can easily change. Please also note that I intend
to achieve the goals without breaking plugin API/ABI.
The concept:
The basic idea is that proxy plugins initially call a Geany API to
register themselves as proxies, providing criterias to select potential
plugins (for now, this is only a list of file extensions) and a few
hooks to call into the plugin when Geany needs it.
Geany will match files against these criterias and, on match, call into
the plugin for the first time. This call should probe whether or not the
plugin can actually handle the plugin. I think this is needed because a)
criterias/file extensions might be ambiguous and b) the plugin might be
written against an incompatible version of the proxy (think python 2 vs 3).
Then when Geany generates the plugin list (i.e. when the user opens
plugin manager (PM) dialog) it'll call a second time into the proxy.
This time the purpose is to load the actual plugin, and install
plugin-specific init(), configure(), help() and cleanup() hooks. Unlike
in classic plugins these hooks must call into proxy, where they have to
be dispatched to call the actual plugin code (this is why we call them
proxy right?).
Once loaded, Geany generally doesn't know/care about the difference
between classic plugins and proxied plugins. This achieves the ultimate
goal: That proxied plugins transparently integrate into the PM dialog
and become first-class citizens.
Part of the proposed concept is to add a "fake proxy" for the builtin
.so-file support. This enables to use the same code for all plugins
(proxied or not). This should greatly reduce the maintenance effort. The
fake proxy naturally must be compiled in but otherwise exposes the same
APIs as actual proxies.
The APIs:
This propsal adds 3 major functions and alters the 4 existing plugin hooks.
plugin_register_proxy(GeanyPlugin *proxy_plugin, ProxyPluginInfo *info,
gpointer user_data);
This is initially called by the proxy and lets Geany know about it.
ProxyPluginInfo contains the criterias and pointers to the probe() and
load() functions. user_data is proxy-specific and passed to probe().
gboolean (*probe)(const gchar *file, gpointer user_data, gpointer
*plugin_data);
This is implemented in the proxy and should return true when it can
handle the plugin, it basically replaces the existing
utils_str_casecmp(G_MODULE_SUFFIX, ...) call. There is a catch though,
while probe() should be as fast as possible, I expect that some proxies
still need to load the file half-way or even in full to make that
decision. In order to maintain that state, it can set the plugin_data
pointer. This will be passed to the load function. This way loading the
plugin again can be avoided.
gboolean (*load)(const gchar *file, gpointer user_data, gpointer
*plugin_data);
The same function signature, but a different purpose. The proxy should
now fully load the plugin specified with file such that is ready to run
(it has the same signature in case it needs to load in probe() already,
then this function can be the same as probe()).
As for the existing hooks, these need gain a parameter (gpointer
plugin_data). Because the hooks can be indirect now, the proxy needs
plugin_data to be able to properly dispatch the hooks on a per-plugin
basis. I.e. the hooks become:
void (*init) (GeanyData *data, gpointer plugin_data);
GtkWidget* (*configure) (GtkDialog *dialog, gpointer plugin_data);
void (*configure_single) (GtkWidget *parent, gpointer plugin_data);
void (*help) (gpointer plugin_data);
void (*cleanup) (gpointer plugin_data);
Because the plugin_data parameter is exclusively for the proxy, the
actual plugins do not receive it. They still implement the
non-plugin_data variant. The parameter is added to the end so that these
can still point to the module symbols for .so file plugins.
That's it so far. I think this proposal should allow to reach our goal
(first class plugin scripts) while avoiding to break plugins ABI/API.
Best regards.
More information about the Devel
mailing list