Branch: refs/heads/master Author: Thomas Martitz kugel@rockbox.org Committer: Thomas Martitz kugel@rockbox.org Date: Sun, 23 Aug 2015 13:23:24 UTC Commit: f2579141bb4188d4fc97eee494ba36e809661ddf https://github.com/geany/geany/commit/f2579141bb4188d4fc97eee494ba36e809661d...
Log Message: ----------- plugins: Replace geany_plugin_register() pdata with a separate API function
The API function adds a free_func parameter, and can also be called after geany_plugin_register(), i.e. in the plugin's init() callback. This fixes a by-design memory leak and gives greater flexibility.
Modified Paths: -------------- src/plugindata.h src/pluginprivate.h src/plugins.c src/pluginutils.c
Modified: src/plugindata.h 7 lines changed, 4 insertions(+), 3 deletions(-) =================================================================== @@ -305,7 +305,8 @@ struct GeanyPluginFuncs };
gboolean geany_plugin_register(GeanyPlugin *plugin, gint api_version, gint min_api_version, - gint abi_version, gpointer pdata); + gint abi_version); +void geany_plugin_set_data(GeanyPlugin *plugin, gpointer data, GDestroyNotify destroy_notify);
/** Convinience macro to register a plugin. * @@ -313,9 +314,9 @@ gboolean geany_plugin_register(GeanyPlugin *plugin, gint api_version, gint min_a * * @since 1.26 (API 225) **/ -#define GEANY_PLUGIN_REGISTER(plugin, min_api_version, pdata) \ +#define GEANY_PLUGIN_REGISTER(plugin, min_api_version) \ geany_plugin_register((plugin), GEANY_API_VERSION, \ - (min_api_version), GEANY_ABI_VERSION, pdata) + (min_api_version), GEANY_ABI_VERSION)
/* Deprecated aliases */ #ifndef GEANY_DISABLE_DEPRECATED
Modified: src/pluginprivate.h 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -81,6 +81,7 @@ typedef struct GeanyPluginPrivate GList *sources; /* GSources to destroy when unloading */
gpointer cb_data; /* user data passed back to functions in GeanyPluginFuncs */ + GDestroyNotify cb_data_destroy; /* called when the plugin is unloaded, for cb_data */ LoadedFlags flags; /* bit-or of LoadedFlags */ } GeanyPluginPrivate;
Modified: src/plugins.c 12 lines changed, 8 insertions(+), 4 deletions(-) =================================================================== @@ -280,7 +280,6 @@ static gint cmp_plugin_names(gconstpointer a, gconstpointer b) * @param api_version The API version the plugin is compiled against (pass GEANY_API_VERSION) * @param min_api_version The minimum API version required by the plugin * @param abi_version The exact ABI version the plugin is compiled against (pass GEANY_ABI_VERSION) - * @param pdata A data pointer to store plugin-specific data, will be passed to the plugin's callbacks * * @return TRUE if the plugin was successfully registered. Otherwise FALSE. * @@ -289,7 +288,7 @@ static gint cmp_plugin_names(gconstpointer a, gconstpointer b) **/ GEANY_API_SYMBOL gboolean geany_plugin_register(GeanyPlugin *plugin, gint api_version, gint min_api_version, - gint abi_version, gpointer pdata) + gint abi_version) { Plugin *p; GeanyPluginFuncs *cbs = plugin->funcs; @@ -531,6 +530,8 @@ plugin_new(const gchar *fname, gboolean load_plugin, gboolean add_to_list) return plugin;
err: + if (plugin->cb_data_destroy) + plugin->cb_data_destroy(plugin->cb_data); if (! g_module_close(module)) g_warning("%s: %s", fname, g_module_error()); g_free(plugin->filename); @@ -646,12 +647,15 @@ plugin_free(Plugin *plugin) plugin_cleanup(plugin);
active_plugin_list = g_list_remove(active_plugin_list, plugin); + plugin_list = g_list_remove(plugin_list, plugin); + + /* cb_data_destroy might be plugin code and must be called before unloading the module */ + if (plugin->cb_data_destroy) + plugin->cb_data_destroy(plugin->cb_data);
if (! g_module_close(plugin->module)) g_warning("%s: %s", plugin->filename, g_module_error());
- plugin_list = g_list_remove(plugin_list, plugin); - g_free(plugin->filename); g_free(plugin); plugin = NULL;
Modified: src/pluginutils.c 47 lines changed, 47 insertions(+), 0 deletions(-) =================================================================== @@ -520,4 +520,51 @@ void plugin_builder_connect_signals(GeanyPlugin *plugin, }
+/** Add additional data that corresponds to the plugin. + * + * This is the data pointer passed to the individual plugin callbacks. It may be + * called as soon as geany_plugin_register() was called with success. When the + * plugin is unloaded, @a free_func is invoked for the data, which connects the + * data to the plugin's own life time. + * + * One intended use case is to set GObjects as data and have them destroyed automatically + * by passing g_object_unref() as @a free_func, so that member functions can be used + * for the @ref GeanyPluginFuncs (via wrappers) but you can set completely custom data. + * + * Be aware that this can only be called once. + * + * @param plugin The plugin provided by Geany + * @param pdata The plugin's data to associate, must not be @c NULL + * @param free_func The destroy notify + * + * @since 1.26 (API 225) + */ +GEANY_API_SYMBOL +void geany_plugin_set_data(GeanyPlugin *plugin, gpointer pdata, GDestroyNotify free_func) +{ + Plugin *p = plugin->priv; + + g_return_if_fail(PLUGIN_LOADED_OK(p)); + /* Do not allow calling this only to set a notify. */ + g_return_if_fail(pdata != NULL); + /* The rationale to allow only setting the data once is the following: + * In the future we want to support proxy plugins (which bind non-C plugins to + * Geany's plugin api). These proxy plugins might need to own the data pointer + * on behalf of the proxied plugin. However, if not, then the plugin should be + * free to use it. This way we can make sure the plugin doesn't accidently trash + * its proxy. + * + * Better a more limited API now that can be opened up later than a potentially + * wrong one that can only be replaced by another one. */ + if (p->cb_data != NULL || p->cb_data_destroy != NULL) + { + g_warning("Double call to %s(), ignored!", G_STRFUNC); + return; + } + + p->cb_data = pdata; + p->cb_data_destroy = free_func; +} + + #endif
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).