Browse Source

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

Added to `Object` and `Signal`
A Thousand Ships 1 year ago
parent
commit
203d3be200

+ 19 - 0
core/object/object.cpp

@@ -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);

+ 1 - 0
core/object/object.h

@@ -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) {

+ 7 - 0
core/variant/callable.cpp

@@ -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) {

+ 1 - 0
core/variant/callable.h

@@ -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);

+ 1 - 0
core/variant/variant_call.cpp

@@ -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);
 
 

+ 8 - 0
doc/classes/Object.xml

@@ -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" />

+ 6 - 0
doc/classes/Signal.xml

@@ -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" />

+ 5 - 0
scene/main/node.cpp

@@ -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

+ 1 - 0
scene/main/node.h

@@ -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();