[Core] Add way to check if a signal has any connections

Added to `Object` and `Signal`
This commit is contained in:
A Thousand Ships 2024-01-18 17:20:56 +01:00
parent 2be730a05b
commit 203d3be200
No known key found for this signature in database
GPG Key ID: 2033189A662F8BD7
9 changed files with 49 additions and 0 deletions

View File

@ -1457,6 +1457,24 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable
return s->slot_map.has(*p_callable.get_base_comparator()); return s->slot_map.has(*p_callable.get_base_comparator());
} }
bool Object::has_connections(const StringName &p_signal) const {
const SignalData *s = signal_map.getptr(p_signal);
if (!s) {
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
if (signal_is_valid) {
return false;
}
if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) {
return false;
}
ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + ".");
}
return !s->slot_map.is_empty();
}
void Object::disconnect(const StringName &p_signal, const Callable &p_callable) { void Object::disconnect(const StringName &p_signal, const Callable &p_callable) {
_disconnect(p_signal, p_callable); _disconnect(p_signal, p_callable);
} }
@ -1697,6 +1715,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "flags"), &Object::connect, DEFVAL(0)); ClassDB::bind_method(D_METHOD("connect", "signal", "callable", "flags"), &Object::connect, DEFVAL(0));
ClassDB::bind_method(D_METHOD("disconnect", "signal", "callable"), &Object::disconnect); ClassDB::bind_method(D_METHOD("disconnect", "signal", "callable"), &Object::disconnect);
ClassDB::bind_method(D_METHOD("is_connected", "signal", "callable"), &Object::is_connected); ClassDB::bind_method(D_METHOD("is_connected", "signal", "callable"), &Object::is_connected);
ClassDB::bind_method(D_METHOD("has_connections", "signal"), &Object::has_connections);
ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals); ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals);
ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals); ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals);

View File

@ -932,6 +932,7 @@ public:
MTVIRTUAL Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0); MTVIRTUAL Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0);
MTVIRTUAL void disconnect(const StringName &p_signal, const Callable &p_callable); MTVIRTUAL void disconnect(const StringName &p_signal, const Callable &p_callable);
MTVIRTUAL bool is_connected(const StringName &p_signal, const Callable &p_callable) const; MTVIRTUAL bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
MTVIRTUAL bool has_connections(const StringName &p_signal) const;
template <typename... VarArgs> template <typename... VarArgs>
void call_deferred(const StringName &p_name, VarArgs... p_args) { void call_deferred(const StringName &p_name, VarArgs... p_args) {

View File

@ -545,6 +545,13 @@ bool Signal::is_connected(const Callable &p_callable) const {
return obj->is_connected(name, p_callable); return obj->is_connected(name, p_callable);
} }
bool Signal::has_connections() const {
Object *obj = get_object();
ERR_FAIL_NULL_V(obj, false);
return obj->has_connections(name);
}
Array Signal::get_connections() const { Array Signal::get_connections() const {
Object *obj = get_object(); Object *obj = get_object();
if (!obj) { if (!obj) {

View File

@ -192,6 +192,7 @@ public:
Error connect(const Callable &p_callable, uint32_t p_flags = 0); Error connect(const Callable &p_callable, uint32_t p_flags = 0);
void disconnect(const Callable &p_callable); void disconnect(const Callable &p_callable);
bool is_connected(const Callable &p_callable) const; bool is_connected(const Callable &p_callable) const;
bool has_connections() const;
Array get_connections() const; Array get_connections() const;
Signal(const Object *p_object, const StringName &p_name); Signal(const Object *p_object, const StringName &p_name);

View File

@ -2121,6 +2121,7 @@ static void _register_variant_builtin_methods_misc() {
bind_method(Signal, disconnect, sarray("callable"), varray()); bind_method(Signal, disconnect, sarray("callable"), varray());
bind_method(Signal, is_connected, sarray("callable"), varray()); bind_method(Signal, is_connected, sarray("callable"), varray());
bind_method(Signal, get_connections, sarray(), varray()); bind_method(Signal, get_connections, sarray(), varray());
bind_method(Signal, has_connections, sarray(), varray());
bind_custom(Signal, emit, _VariantCall::func_Signal_emit, false, Variant); bind_custom(Signal, emit, _VariantCall::func_Signal_emit, false, Variant);

View File

@ -824,6 +824,14 @@
Returns the name of the translation domain used by [method tr] and [method tr_n]. See also [TranslationServer]. Returns the name of the translation domain used by [method tr] and [method tr_n]. See also [TranslationServer].
</description> </description>
</method> </method>
<method name="has_connections" qualifiers="const">
<return type="bool" />
<param index="0" name="signal" type="StringName" />
<description>
Returns [code]true[/code] if any connection exists on the given [param signal] name.
[b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call.
</description>
</method>
<method name="has_meta" qualifiers="const"> <method name="has_meta" qualifiers="const">
<return type="bool" /> <return type="bool" />
<param index="0" name="name" type="StringName" /> <param index="0" name="name" type="StringName" />

View File

@ -109,6 +109,12 @@
Returns the ID of the object emitting this signal (see [method Object.get_instance_id]). Returns the ID of the object emitting this signal (see [method Object.get_instance_id]).
</description> </description>
</method> </method>
<method name="has_connections" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if any [Callable] is connected to this signal.
</description>
</method>
<method name="is_connected" qualifiers="const"> <method name="is_connected" qualifiers="const">
<return type="bool" /> <return type="bool" />
<param index="0" name="callable" type="Callable" /> <param index="0" name="callable" type="Callable" />

View File

@ -4019,4 +4019,9 @@ bool Node::is_connected(const StringName &p_signal, const Callable &p_callable)
return Object::is_connected(p_signal, p_callable); return Object::is_connected(p_signal, p_callable);
} }
bool Node::has_connections(const StringName &p_signal) const {
ERR_THREAD_GUARD_V(false);
return Object::has_connections(p_signal);
}
#endif #endif

View File

@ -797,6 +797,7 @@ public:
virtual Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0) override; virtual Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0) override;
virtual void disconnect(const StringName &p_signal, const Callable &p_callable) override; virtual void disconnect(const StringName &p_signal, const Callable &p_callable) override;
virtual bool is_connected(const StringName &p_signal, const Callable &p_callable) const override; virtual bool is_connected(const StringName &p_signal, const Callable &p_callable) const override;
virtual bool has_connections(const StringName &p_signal) const override;
#endif #endif
Node(); Node();
~Node(); ~Node();