On Saturday, August 16, 2003, at 02:53 PM, Fred. Oger wrote:
Could someone tell me how I can disconnect a signal from a widget by function name ? Tried : $widget->handlers_signal_disconnect_by_func(\&CheckAndSaveCustomer);$widget- >Glib::handlers_signal_disconnect_by_func(\&CheckAndSaveCustomer);none of them passed. How am I supposed to use this function call ?
well, right now, you can't --- it's not bound to perl. if it were bound it would be $widget->signal_handler_disconnect_by_func (func, data) since the C function is g_signal_handler_disconnect_by_func (instance, func, data) and the GSignal strips only the g_ prefix.[1]$object->disconnect ($id) works, but obviously doesn't do the same thing, as it disconnects one at a time and requires you to store the handler tags.
the next question would be "why isn't it implemented?" the answer is, "because there's not a clean way to do it." g_signal_handlers_disconnect_by_func() takes a pointer to a C function, and as such is useless for language bindings. even the API reference says so. the real thing to do would be to bind g_signal_handlers_disconnect_matched(), for which disconnect_by_func() is merely a convenient wrapper.
most of the signal functions actually work with GClosures, which are GLib's representation of functions as first-class objects. the perl bindings completely replace the idea of a GClosure with a perl code reference[3]. GPerlClosure, the bindings' specialized version of GClosure which knows how to marshal perl subroutines, stores a copy of the scalar that points to the code to be run. if we wanted to look up signal handlers by function, we'd have to look through the lists of GClosures for matching callback SVs --- but the closure lists are private to libgobject.
that means that in order to implement (disconnect|block|unblock)_by_func or (disconnect|block|unblock)_matched, the bindings actually have to keep their own list of all the GPerlClosures connected via gperl_signal_connect.
i do have a working implementation that i whipped up while trying to answer this message, but i am hesitant to commit it, because i don't really like the solution (duplication of data, overhead and performance penalties, general fragility).
the code is attached, please let me know what you think.
Attachment:
signal_stuff.patch
Description: Binary data
-[1] why does it strip only g_ when you'd think it should strip g_signal_? it's a messy issue.
the GSignal stuff doesn't really work in a terribly straightforward object-method way... in fact, signal_connect really isn't a method of an object, as you can use *anything* as the instance in C (instance is a gpointer, which is GLib-ese for (void*))[2], but
Glib::Signal->connect ($instance, name => $handler) arguably isn't as easy to follow as $instance->signal_connect (name => $handler).but the true reason is more that gtk-perl set the precedent and we're sticking to it.
[2] by contrast, g_signal_handler_block and g_signal_handler_disconnect work on GObjects rather than gpointers.
[3] in fact, perl actually just uses scalars as subroutine references. as a side effect of call_sv, if you have strict subs turned off, you can actually pass a string to signal_connect as the subroutine name, and perl will call it correctly. i don't recommend or condone this in anyway, but it works.