[geany/geany] f25791: plugins: Replace geany_plugin_register() pdata with a separate API function

Thomas Martitz git-noreply at xxxxx
Sun Aug 23 13:23:24 UTC 2015


Branch:      refs/heads/master
Author:      Thomas Martitz <kugel at rockbox.org>
Committer:   Thomas Martitz <kugel at rockbox.org>
Date:        Sun, 23 Aug 2015 13:23:24 UTC
Commit:      f2579141bb4188d4fc97eee494ba36e809661ddf
             https://github.com/geany/geany/commit/f2579141bb4188d4fc97eee494ba36e809661ddf

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).


More information about the Commits mailing list