signal: return TRUE from g_signal_has_handler_pending for custom class closure

This is almost always what you want, because if you're using this you
want to know if any "custom code" (i.e. not the default class closure)
is going to be run if you emit this signal.

I looked at all the existing uses of this and they were all broken in the
presence of g_signal_override_class_closure().

https://bugzilla.gnome.org/show_bug.cgi?id=754986
This commit is contained in:
Alexander Larsson 2015-09-14 13:15:51 +02:00
parent 2e96668f24
commit 69002f726d

View File

@ -1526,7 +1526,14 @@ signal_find_class_closure (SignalNode *node,
ClassClosure key;
/* cc->instance_type is 0 for default closure */
if (g_bsearch_array_get_n_nodes (bsa) == 1)
{
cc = g_bsearch_array_get_nth (bsa, &g_class_closure_bconfig, 0);
if (cc && cc->instance_type == 0) /* check for default closure */
return cc;
}
key.instance_type = itype;
cc = g_bsearch_array_lookup (bsa, &g_class_closure_bconfig, &key);
while (!cc && key.instance_type)
@ -1546,12 +1553,6 @@ signal_lookup_closure (SignalNode *node,
{
ClassClosure *cc;
if (node->class_closure_bsa && g_bsearch_array_get_n_nodes (node->class_closure_bsa) == 1)
{
cc = g_bsearch_array_get_nth (node->class_closure_bsa, &g_class_closure_bconfig, 0);
if (cc && cc->instance_type == 0) /* check for default closure */
return cc->closure;
}
cc = signal_find_class_closure (node, G_TYPE_FROM_INSTANCE (instance));
return cc ? cc->closure : NULL;
}
@ -2951,6 +2952,9 @@ g_signal_handlers_disconnect_matched (gpointer instance,
* consistent with how a signal emitted with @detail would be delivered
* to those handlers.
*
* Since 2.46 this also checks for a non-default class closure being
* installed, as this is basically always what you want.
*
* One example of when you might use this is when the arguments to the
* signal are difficult to compute. A class implementor may opt to not
* emit the signal if no one is attached anyway, thus saving the cost
@ -2967,15 +2971,16 @@ g_signal_has_handler_pending (gpointer instance,
{
HandlerMatch *mlist;
gboolean has_pending;
SignalNode *node;
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
g_return_val_if_fail (signal_id > 0, FALSE);
SIGNAL_LOCK ();
node = LOOKUP_SIGNAL_NODE (signal_id);
if (detail)
{
SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
if (!(node->flags & G_SIGNAL_DETAILED))
{
g_warning ("%s: signal id '%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
@ -2992,9 +2997,15 @@ g_signal_has_handler_pending (gpointer instance,
handler_match_free1_R (mlist, instance);
}
else
has_pending = FALSE;
{
ClassClosure *class_closure = signal_find_class_closure (node, G_TYPE_FROM_INSTANCE (instance));
if (class_closure != NULL && class_closure->instance_type != 0)
has_pending = TRUE;
else
has_pending = FALSE;
}
SIGNAL_UNLOCK ();
return has_pending;
}