Merge branch '1.25/safer-plugin_signal_connect'
This commit is contained in:
commit
8f713377c4
@ -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 */
|
||||
|
@ -61,4 +61,7 @@ GeanyPluginPrivate;
|
||||
typedef GeanyPluginPrivate Plugin; /* shorter alias */
|
||||
|
||||
|
||||
void plugin_watch_object(Plugin *plugin, gpointer object);
|
||||
|
||||
|
||||
#endif /* GEANY_PLUGINPRIVATE_H */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user