[geany/geany] 8f7133: Merge branch '1.25/safer-plugin_signal_connect'
Colomban Wendling
git-noreply at xxxxx
Sun Apr 13 18:07:26 UTC 2014
Branch: refs/heads/master
Author: Colomban Wendling <ban at herbesfolles.org>
Committer: Colomban Wendling <ban at herbesfolles.org>
Date: Sun, 13 Apr 2014 18:07:26 UTC
Commit: 8f713377c403e6b0368ff1aae918876f756c1564
https://github.com/geany/geany/commit/8f713377c403e6b0368ff1aae918876f756c1564
Log Message:
-----------
Merge branch '1.25/safer-plugin_signal_connect'
Modified Paths:
--------------
src/plugindata.h
src/pluginprivate.h
src/plugins.c
src/pluginutils.c
Modified: src/plugindata.h
2 files changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -55,7 +55,7 @@ G_BEGIN_DECLS
* @warning You should not test for values below 200 as previously
* @c GEANY_API_VERSION was defined as an enum value, not a macro.
*/
-#define GEANY_API_VERSION 217
+#define GEANY_API_VERSION 218
/* hack to have a different ABI when built with GTK3 because loading GTK2-linked plugins
* with GTK3-linked Geany leads to crash */
Modified: src/pluginprivate.h
3 files changed, 3 insertions(+), 0 deletions(-)
===================================================================
@@ -61,4 +61,7 @@ GeanyPluginPrivate;
typedef GeanyPluginPrivate Plugin; /* shorter alias */
+void plugin_watch_object(Plugin *plugin, gpointer object);
+
+
#endif /* GEANY_PLUGINPRIVATE_H */
Modified: src/plugins.c
34 files changed, 34 insertions(+), 0 deletions(-)
===================================================================
@@ -769,6 +769,37 @@ plugin_new(const gchar *fname, gboolean init_plugin, gboolean add_to_list)
}
+static void on_object_weak_notify(gpointer data, GObject *old_ptr)
+{
+ Plugin *plugin = data;
+ guint i = 0;
+
+ g_return_if_fail(plugin && plugin->signal_ids);
+
+ for (i = 0; i < plugin->signal_ids->len; i++)
+ {
+ SignalConnection *sc = &g_array_index(plugin->signal_ids, SignalConnection, i);
+
+ if (sc->object == old_ptr)
+ {
+ g_array_remove_index_fast(plugin->signal_ids, i);
+ /* we can break the loop right after finding the first match,
+ * because we will get one notification per connected signal */
+ break;
+ }
+ }
+}
+
+
+/* add an object to watch for destruction, and release pointers to it when destroyed.
+ * this should only be used by plugin_signal_connect() to add a watch on
+ * the object lifetime and nuke out references to it in plugin->signal_ids */
+void plugin_watch_object(Plugin *plugin, gpointer object)
+{
+ g_object_weak_ref(object, on_object_weak_notify, plugin);
+}
+
+
static void remove_callbacks(Plugin *plugin)
{
GArray *signal_ids = plugin->signal_ids;
@@ -778,7 +809,10 @@ static void remove_callbacks(Plugin *plugin)
return;
foreach_array(SignalConnection, sc, signal_ids)
+ {
g_signal_handler_disconnect(sc->object, sc->handler_id);
+ g_object_weak_unref(sc->object, on_object_weak_notify, plugin);
+ }
g_array_free(signal_ids, TRUE);
}
Modified: src/pluginutils.c
14 files changed, 12 insertions(+), 2 deletions(-)
===================================================================
@@ -105,7 +105,8 @@ void plugin_module_make_resident(GeanyPlugin *plugin)
* @param user_data The user data passed to the signal handler.
* @see plugin_callbacks.
*
- * @warning This should only be used on objects that outlive the plugin, never on
+ * @warning Before version 1.25 (API < 218),
+ * this should only be used on objects that outlive the plugin, never on
* objects that will get destroyed before the plugin is unloaded. For objects
* created and destroyed by the plugin, you can simply use @c g_signal_connect(),
* since all handlers are disconnected when the object is destroyed anyway.
@@ -116,7 +117,10 @@ void plugin_module_make_resident(GeanyPlugin *plugin)
* disconnect the signal on @c plugin_cleanup()), and when the object is destroyed
* during the plugin's lifetime (in which case you cannot and should not disconnect
* manually in @c plugin_cleanup() since it already has been disconnected and the
- * object has been destroyed), and disconnect yourself or not as appropriate. */
+ * object has been destroyed), and disconnect yourself or not as appropriate.
+ * @note Since version 1.25 (API >= 218), the object lifetime is watched and so the above
+ * restriction does not apply. However, for objects destroyed by the plugin,
+ * @c g_signal_connect() is safe and has lower overhead. */
void plugin_signal_connect(GeanyPlugin *plugin,
GObject *object, const gchar *signal_name, gboolean after,
GCallback callback, gpointer user_data)
@@ -124,6 +128,9 @@ void plugin_signal_connect(GeanyPlugin *plugin,
gulong id;
SignalConnection sc;
+ g_return_if_fail(plugin != NULL);
+ g_return_if_fail(object == NULL || G_IS_OBJECT(object));
+
if (!object)
object = geany_object;
@@ -137,6 +144,9 @@ void plugin_signal_connect(GeanyPlugin *plugin,
sc.object = object;
sc.handler_id = id;
g_array_append_val(plugin->priv->signal_ids, sc);
+
+ /* watch the object lifetime to nuke our pointers to it */
+ plugin_watch_object(plugin->priv, object);
}
--------------
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