One-shot signal handlers
Sometimes I want to have a signal handler that changes something the very first time a signal is emitted. This is hard to do in languages like Rust - Rust uses closures for signal handling, and we can't disconnect_by_func
, so we need to manually manage the SignalHandlerId
. This can get difficult with Rust due to the strict ownership rules.
@ZanderBrown came up with a prototype for a g_oneshot ()
API that handles this:
include "g-oneshot.h"
typedef struct {
gulong handle;
} GOneshot;
static void
g_oneshot_free (gpointer data,
GClosure *closure)
{
GOneshot *oneshot = data;
g_free (oneshot);
}
static void
g_oneshot_fire (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
GObject *obj = g_value_get_object (¶m_values[0]);
GOneshot *oneshot = marshal_data;
if (!oneshot->handle) {
return;
}
closure->marshal (closure,
return_value,
n_param_values,
param_values,
invocation_hint,
((GCClosure *) closure)->callback);
g_clear_signal_handler (&oneshot->handle, obj);
}
gulong
g_oneshot (GObject *obj,
const char *name,
GCallback callback,
gpointer user_data)
{
GClosure *closure;
GOneshot *oneshot = g_new0 (GOneshot, 1);
closure = g_cclosure_new (callback, user_data, NULL);
oneshot->handle = g_signal_connect_closure (obj, name, closure, FALSE);
g_closure_set_meta_marshal (closure, oneshot, g_oneshot_fire);
g_closure_add_finalize_notifier (closure, oneshot, g_oneshot_free);
return oneshot->handle;
}
I think this would be something neat to have in glib, so I wanted to open this issue for discussion.