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
|
* @warning You should not test for values below 200 as previously
|
||||||
* @c GEANY_API_VERSION was defined as an enum value, not a macro.
|
* @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
|
/* hack to have a different ABI when built with GTK3 because loading GTK2-linked plugins
|
||||||
* with GTK3-linked Geany leads to crash */
|
* with GTK3-linked Geany leads to crash */
|
||||||
|
@ -61,4 +61,7 @@ GeanyPluginPrivate;
|
|||||||
typedef GeanyPluginPrivate Plugin; /* shorter alias */
|
typedef GeanyPluginPrivate Plugin; /* shorter alias */
|
||||||
|
|
||||||
|
|
||||||
|
void plugin_watch_object(Plugin *plugin, gpointer object);
|
||||||
|
|
||||||
|
|
||||||
#endif /* GEANY_PLUGINPRIVATE_H */
|
#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)
|
static void remove_callbacks(Plugin *plugin)
|
||||||
{
|
{
|
||||||
GArray *signal_ids = plugin->signal_ids;
|
GArray *signal_ids = plugin->signal_ids;
|
||||||
@ -778,7 +809,10 @@ static void remove_callbacks(Plugin *plugin)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
foreach_array(SignalConnection, sc, signal_ids)
|
foreach_array(SignalConnection, sc, signal_ids)
|
||||||
|
{
|
||||||
g_signal_handler_disconnect(sc->object, sc->handler_id);
|
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);
|
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.
|
* @param user_data The user data passed to the signal handler.
|
||||||
* @see plugin_callbacks.
|
* @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
|
* 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(),
|
* 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.
|
* 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
|
* 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
|
* 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
|
* 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,
|
void plugin_signal_connect(GeanyPlugin *plugin,
|
||||||
GObject *object, const gchar *signal_name, gboolean after,
|
GObject *object, const gchar *signal_name, gboolean after,
|
||||||
GCallback callback, gpointer user_data)
|
GCallback callback, gpointer user_data)
|
||||||
@ -124,6 +128,9 @@ void plugin_signal_connect(GeanyPlugin *plugin,
|
|||||||
gulong id;
|
gulong id;
|
||||||
SignalConnection sc;
|
SignalConnection sc;
|
||||||
|
|
||||||
|
g_return_if_fail(plugin != NULL);
|
||||||
|
g_return_if_fail(object == NULL || G_IS_OBJECT(object));
|
||||||
|
|
||||||
if (!object)
|
if (!object)
|
||||||
object = geany_object;
|
object = geany_object;
|
||||||
|
|
||||||
@ -137,6 +144,9 @@ void plugin_signal_connect(GeanyPlugin *plugin,
|
|||||||
sc.object = object;
|
sc.object = object;
|
||||||
sc.handler_id = id;
|
sc.handler_id = id;
|
||||||
g_array_append_val(plugin->priv->signal_ids, sc);
|
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