feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -292,6 +292,13 @@ void CanvasItem::_exit_canvas() {
void CanvasItem::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
RID ae = get_accessibility_element();
ERR_FAIL_COND(ae.is_null());
DisplayServer::get_singleton()->accessibility_update_set_flag(ae, DisplayServer::AccessibilityFlags::FLAG_HIDDEN, !visible);
} break;
case NOTIFICATION_ENTER_TREE: {
ERR_MAIN_THREAD_GUARD;
ERR_FAIL_COND(!is_inside_tree());
@ -743,7 +750,7 @@ void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_sta
Point2 *points_ptr = points.ptrw();
// Clamp angle difference to full circle so arc won't overlap itself.
const real_t delta_angle = CLAMP(p_end_angle - p_start_angle, -Math_TAU, Math_TAU);
const real_t delta_angle = CLAMP(p_end_angle - p_start_angle, -Math::TAU, Math::TAU);
for (int i = 0; i < p_point_count; i++) {
real_t theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
points_ptr[i] = p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius;
@ -816,7 +823,7 @@ void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &
points.resize(circle_segments + 1);
Vector2 *points_ptr = points.ptrw();
const real_t circle_point_step = Math_TAU / circle_segments;
const real_t circle_point_step = Math::TAU / circle_segments;
for (int i = 0; i < circle_segments; i++) {
float angle = i * circle_point_step;
@ -1245,6 +1252,38 @@ void CanvasItem::_validate_property(PropertyInfo &p_property) const {
}
}
PackedStringArray CanvasItem::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
if (clip_children_mode != CLIP_CHILDREN_DISABLED && is_inside_tree()) {
bool warned_about_ancestor_clipping = false;
bool warned_about_canvasgroup_ancestor = false;
Node *n = get_parent();
while (n) {
CanvasItem *as_canvas_item = Object::cast_to<CanvasItem>(n);
if (!warned_about_ancestor_clipping && as_canvas_item && as_canvas_item->clip_children_mode != CLIP_CHILDREN_DISABLED) {
warnings.push_back(vformat(RTR("Ancestor \"%s\" clips its children, so this node will not be able to clip its children."), as_canvas_item->get_name()));
warned_about_ancestor_clipping = true;
}
CanvasGroup *as_canvas_group = Object::cast_to<CanvasGroup>(n);
if (!warned_about_canvasgroup_ancestor && as_canvas_group) {
warnings.push_back(vformat(RTR("Ancestor \"%s\" is a CanvasGroup, so this node will not be able to clip its children."), as_canvas_group->get_name()));
warned_about_canvasgroup_ancestor = true;
}
// Only break out early once both warnings have been triggered, so
// that the user is aware of both possible reasons for clipping not working.
if (warned_about_ancestor_clipping && warned_about_canvasgroup_ancestor) {
break;
}
n = n->get_parent();
}
}
return warnings;
}
void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("_top_level_raise_self"), &CanvasItem::_top_level_raise_self);
@ -1646,6 +1685,8 @@ void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
}
clip_children_mode = p_clip_mode;
update_configuration_warnings();
if (Object::cast_to<CanvasGroup>(this) != nullptr) {
//avoid accidental bugs, make this not work on CanvasGroup
return;
@ -1653,6 +1694,7 @@ void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
}
CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
ERR_READ_THREAD_GUARD_V(CLIP_CHILDREN_DISABLED);
return clip_children_mode;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CANVAS_ITEM_H
#define CANVAS_ITEM_H
#pragma once
#include "scene/main/node.h"
#include "scene/resources/font.h"
@ -399,6 +398,8 @@ public:
int get_canvas_layer() const;
CanvasLayer *get_canvas_layer_node() const;
virtual PackedStringArray get_configuration_warnings() const override;
CanvasItem();
~CanvasItem();
};
@ -460,5 +461,3 @@ public:
CanvasTexture();
~CanvasTexture();
};
#endif // CANVAS_ITEM_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CANVAS_LAYER_H
#define CANVAS_LAYER_H
#pragma once
#include "scene/main/node.h"
@ -111,5 +110,3 @@ public:
CanvasLayer();
~CanvasLayer();
};
#endif // CANVAS_LAYER_H

View file

@ -241,7 +241,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
for (const String &E : rheaders) {
if (E.containsn("Location: ")) {
new_request = E.substr(9, E.length()).strip_edges();
new_request = E.substr(9).strip_edges();
}
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef HTTP_REQUEST_H
#define HTTP_REQUEST_H
#pragma once
#include "core/io/http_client.h"
#include "core/io/stream_peer_gzip.h"
@ -167,5 +166,3 @@ public:
};
VARIANT_ENUM_CAST(HTTPRequest::Result);
#endif // HTTP_REQUEST_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef INSTANCE_PLACEHOLDER_H
#define INSTANCE_PLACEHOLDER_H
#pragma once
#include "scene/main/node.h"
@ -67,5 +66,3 @@ public:
InstancePlaceholder();
};
#endif // INSTANCE_PLACEHOLDER_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef MISSING_NODE_H
#define MISSING_NODE_H
#pragma once
#include "scene/main/node.h"
@ -62,5 +61,3 @@ public:
MissingNode();
};
#endif // MISSING_NODE_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef MULTIPLAYER_API_H
#define MULTIPLAYER_API_H
#pragma once
#include "core/object/ref_counted.h"
#include "scene/main/multiplayer_peer.h"
@ -111,5 +110,3 @@ public:
GDVIRTUAL2R(Error, _object_configuration_add, Object *, Variant);
GDVIRTUAL2R(Error, _object_configuration_remove, Object *, Variant);
};
#endif // MULTIPLAYER_API_H

View file

@ -137,7 +137,7 @@ Error MultiplayerPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buff
return FAILED;
}
if (script_buffer.size() == 0) {
if (script_buffer.is_empty()) {
return Error::ERR_UNAVAILABLE;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef MULTIPLAYER_PEER_H
#define MULTIPLAYER_PEER_H
#pragma once
#include "core/io/packet_peer.h"
@ -146,5 +145,3 @@ public:
EXBIND0RC(int, get_unique_id);
EXBIND0RC(ConnectionStatus, get_connection_status);
};
#endif // MULTIPLAYER_PEER_H

View file

@ -43,14 +43,87 @@
#include "scene/resources/packed_scene.h"
#include "viewport.h"
#include <stdint.h>
int Node::orphan_node_count = 0;
thread_local Node *Node::current_process_thread_group = nullptr;
void Node::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_ACCESSIBILITY_INVALIDATE: {
if (data.accessibility_element.is_valid()) {
DisplayServer::get_singleton()->accessibility_free_element(data.accessibility_element);
data.accessibility_element = RID();
}
} break;
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
RID ae = get_accessibility_element();
ERR_FAIL_COND(ae.is_null());
// Base info.
if (data.parent) {
String container_info = data.parent->get_accessibility_container_name(this);
DisplayServer::get_singleton()->accessibility_update_set_name(ae, container_info.is_empty() ? get_accessibility_name() : get_accessibility_name() + " " + container_info);
} else {
DisplayServer::get_singleton()->accessibility_update_set_name(ae, get_accessibility_name());
}
DisplayServer::get_singleton()->accessibility_update_set_description(ae, get_accessibility_description());
DisplayServer::get_singleton()->accessibility_update_set_live(ae, get_accessibility_live());
// Related nodes.
for (int i = 0; i < data.accessibility_controls_nodes.size(); i++) {
const NodePath &np = data.accessibility_controls_nodes[i];
if (!np.is_empty()) {
Node *n = get_node(np);
if (n && !n->is_part_of_edited_scene()) {
DisplayServer::get_singleton()->accessibility_update_add_related_controls(ae, n->get_accessibility_element());
}
}
}
for (int i = 0; i < data.accessibility_described_by_nodes.size(); i++) {
const NodePath &np = data.accessibility_described_by_nodes[i];
if (!np.is_empty()) {
Node *n = get_node(np);
if (n && !n->is_part_of_edited_scene()) {
DisplayServer::get_singleton()->accessibility_update_add_related_described_by(ae, n->get_accessibility_element());
}
}
}
for (int i = 0; i < data.accessibility_labeled_by_nodes.size(); i++) {
const NodePath &np = data.accessibility_labeled_by_nodes[i];
if (!np.is_empty()) {
Node *n = get_node(np);
if (n && !n->is_part_of_edited_scene()) {
DisplayServer::get_singleton()->accessibility_update_add_related_labeled_by(ae, n->get_accessibility_element());
}
}
}
for (int i = 0; i < data.accessibility_flow_to_nodes.size(); i++) {
const NodePath &np = data.accessibility_flow_to_nodes[i];
if (!np.is_empty()) {
Node *n = get_node(np);
if (n && !n->is_part_of_edited_scene()) {
DisplayServer::get_singleton()->accessibility_update_add_related_flow_to(ae, n->get_accessibility_element());
}
}
}
// Node children.
if (!accessibility_override_tree_hierarchy()) {
for (int i = 0; i < get_child_count(); i++) {
Node *child_node = get_child(i);
Window *child_wnd = Object::cast_to<Window>(child_node);
if (child_wnd && !child_wnd->is_embedded()) {
continue;
}
if (child_node->is_part_of_edited_scene()) {
continue;
}
DisplayServer::get_singleton()->accessibility_update_add_child(ae, child_node->get_accessibility_element());
}
}
} break;
case NOTIFICATION_PROCESS: {
GDVIRTUAL_CALL(_process, get_process_delta_time());
} break;
@ -63,6 +136,16 @@ void Node::_notification(int p_notification) {
ERR_FAIL_NULL(get_viewport());
ERR_FAIL_NULL(get_tree());
if (get_tree()->is_accessibility_supported() && !is_part_of_edited_scene()) {
get_tree()->_accessibility_force_update();
get_tree()->_accessibility_notify_change(this);
if (data.parent) {
get_tree()->_accessibility_notify_change(data.parent);
} else {
get_tree()->_accessibility_notify_change(get_window()); // Root node.
}
}
// Update process mode.
if (data.process_mode == PROCESS_MODE_INHERIT) {
if (data.parent) {
@ -153,6 +236,19 @@ void Node::_notification(int p_notification) {
ERR_FAIL_NULL(get_viewport());
ERR_FAIL_NULL(get_tree());
if (get_tree()->is_accessibility_supported() && !is_part_of_edited_scene()) {
if (data.accessibility_element.is_valid()) {
DisplayServer::get_singleton()->accessibility_free_element(data.accessibility_element);
data.accessibility_element = RID();
}
get_tree()->_accessibility_notify_change(this, true);
if (data.parent) {
get_tree()->_accessibility_notify_change(data.parent);
} else {
get_tree()->_accessibility_notify_change(get_window()); // Root node.
}
}
get_tree()->nodes_in_tree_count--;
orphan_node_count++;
@ -227,10 +323,6 @@ void Node::_notification(int p_notification) {
GDVIRTUAL_CALL(_ready);
} break;
case NOTIFICATION_POSTINITIALIZE: {
data.in_constructor = false;
} break;
case NOTIFICATION_PREDELETE: {
if (data.inside_tree && !Thread::is_main_thread()) {
cancel_free();
@ -1378,7 +1470,95 @@ void Node::_propagate_translation_domain_dirty() {
child->_propagate_translation_domain_dirty();
}
}
notification(NOTIFICATION_TRANSLATION_CHANGED);
if (is_inside_tree() && data.auto_translate_mode != AUTO_TRANSLATE_MODE_DISABLED) {
notification(NOTIFICATION_TRANSLATION_CHANGED);
}
}
void Node::set_accessibility_name(const String &p_name) {
ERR_THREAD_GUARD
if (data.accessibility_name != p_name) {
data.accessibility_name = p_name;
queue_accessibility_update();
update_configuration_warnings();
}
}
String Node::get_accessibility_name() const {
return atr(data.accessibility_name);
}
void Node::set_accessibility_description(const String &p_description) {
ERR_THREAD_GUARD
if (data.accessibility_description != p_description) {
data.accessibility_description = p_description;
queue_accessibility_update();
}
}
String Node::get_accessibility_description() const {
return atr(data.accessibility_description);
}
void Node::set_accessibility_live(DisplayServer::AccessibilityLiveMode p_mode) {
ERR_THREAD_GUARD
if (data.accessibility_live != p_mode) {
data.accessibility_live = p_mode;
queue_accessibility_update();
}
}
DisplayServer::AccessibilityLiveMode Node::get_accessibility_live() const {
return data.accessibility_live;
}
void Node::set_accessibility_controls_nodes(const TypedArray<NodePath> &p_node_path) {
ERR_THREAD_GUARD
if (data.accessibility_controls_nodes != p_node_path) {
data.accessibility_controls_nodes = p_node_path;
queue_accessibility_update();
}
}
TypedArray<NodePath> Node::get_accessibility_controls_nodes() const {
return data.accessibility_controls_nodes;
}
void Node::set_accessibility_described_by_nodes(const TypedArray<NodePath> &p_node_path) {
ERR_THREAD_GUARD
if (data.accessibility_described_by_nodes != p_node_path) {
data.accessibility_described_by_nodes = p_node_path;
queue_accessibility_update();
}
}
TypedArray<NodePath> Node::get_accessibility_described_by_nodes() const {
return data.accessibility_described_by_nodes;
}
void Node::set_accessibility_labeled_by_nodes(const TypedArray<NodePath> &p_node_path) {
ERR_THREAD_GUARD
if (data.accessibility_labeled_by_nodes != p_node_path) {
data.accessibility_labeled_by_nodes = p_node_path;
queue_accessibility_update();
}
}
TypedArray<NodePath> Node::get_accessibility_labeled_by_nodes() const {
return data.accessibility_labeled_by_nodes;
}
void Node::set_accessibility_flow_to_nodes(const TypedArray<NodePath> &p_node_path) {
ERR_THREAD_GUARD
if (data.accessibility_flow_to_nodes != p_node_path) {
data.accessibility_flow_to_nodes = p_node_path;
queue_accessibility_update();
}
}
TypedArray<NodePath> Node::get_accessibility_flow_to_nodes() const {
return data.accessibility_flow_to_nodes;
}
StringName Node::get_name() const {
@ -1461,6 +1641,8 @@ String Node::adjust_name_casing(const String &p_name) {
return p_name.to_camel_case();
case NAME_CASING_SNAKE_CASE:
return p_name.to_snake_case();
case NAME_CASING_KEBAB_CASE:
return p_name.to_kebab_case();
}
return p_name;
}
@ -1637,8 +1819,6 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name, InternalM
}
/* Notify */
//recognize children created in this node constructor
p_child->data.parent_owned = data.in_constructor;
add_child_notify(p_child);
notification(NOTIFICATION_CHILD_ORDER_CHANGED);
emit_signal(SNAME("child_order_changed"));
@ -1698,7 +1878,6 @@ void Node::remove_child(Node *p_child) {
data.blocked++;
p_child->_set_tree(nullptr);
//}
remove_child_notify(p_child);
p_child->notification(NOTIFICATION_UNPARENTED);
@ -1957,6 +2136,7 @@ void Node::reparent(Node *p_parent, bool p_keep_global_transform) {
ERR_THREAD_GUARD
ERR_FAIL_NULL(p_parent);
ERR_FAIL_NULL_MSG(data.parent, "Node needs a parent to be reparented.");
ERR_FAIL_COND_MSG(p_parent == this, vformat("Can't reparent '%s' to itself.", p_parent->get_name()));
if (p_parent == data.parent) {
return;
@ -2683,11 +2863,11 @@ bool Node::is_part_of_edited_scene() const {
void Node::get_storable_properties(HashSet<StringName> &r_storable_properties) const {
ERR_THREAD_GUARD
List<PropertyInfo> pi;
get_property_list(&pi);
for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
if ((E->get().usage & PROPERTY_USAGE_STORAGE)) {
r_storable_properties.insert(E->get().name);
List<PropertyInfo> property_list;
get_property_list(&property_list);
for (const PropertyInfo &pi : property_list) {
if ((pi.usage & PROPERTY_USAGE_STORAGE)) {
r_storable_properties.insert(pi.name);
}
}
}
@ -2792,12 +2972,8 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
instance_roots.push_back(this);
for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
for (int i = 0; i < N->get()->get_child_count(); ++i) {
Node *descendant = N->get()->get_child(i);
if (!descendant->get_owner()) {
continue; // Internal nodes or nodes added by scripts.
}
for (int i = 0; i < N->get()->get_child_count(false); ++i) {
Node *descendant = N->get()->get_child(i, false);
// Skip nodes not really belonging to the instantiated hierarchy; they'll be processed normally later
// but remember non-instantiated nodes that are hidden below instantiated ones
@ -2841,10 +3017,7 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
}
}
for (int i = 0; i < get_child_count(); i++) {
if (get_child(i)->data.parent_owned) {
continue;
}
for (int i = 0; i < get_child_count(false); i++) {
if (instantiated && get_child(i)->data.owner == this) {
continue; //part of instance
}
@ -3038,10 +3211,10 @@ void Node::_duplicate_properties(const Node *p_root, const Node *p_original, Nod
}
}
for (int i = 0; i < p_original->get_child_count(); i++) {
Node *copy_child = p_copy->get_child(i);
for (int i = 0; i < p_original->get_child_count(false); i++) {
Node *copy_child = p_copy->get_child(i, false);
ERR_FAIL_NULL_MSG(copy_child, "Child node disappeared while duplicating.");
_duplicate_properties(p_root, p_original->get_child(i), copy_child, p_flags);
_duplicate_properties(p_root, p_original->get_child(i, false), copy_child, p_flags);
}
}
@ -3072,7 +3245,11 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
if (!target) {
continue;
}
NodePath ptarget = p_original->get_path_to(target);
if (ptarget.is_empty()) {
continue;
}
Node *copytarget = target;
@ -3158,8 +3335,8 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
while (get_child_count()) {
Node *child = get_child(0);
remove_child(child);
if (!child->is_owned_by_parent()) {
// add the custom children to the p_node
if (!child->is_internal()) {
// Add the custom children to the p_node.
Node *child_owner = child->get_owner() == this ? p_node : child->get_owner();
child->set_owner(nullptr);
p_node->add_child(child);
@ -3413,6 +3590,18 @@ void Node::clear_internal_tree_resource_paths() {
}
}
PackedStringArray Node::get_accessibility_configuration_warnings() const {
ERR_THREAD_GUARD_V(PackedStringArray());
PackedStringArray ret;
Vector<String> warnings;
if (GDVIRTUAL_CALL(_get_accessibility_configuration_warnings, warnings)) {
ret.append_array(warnings);
}
return ret;
}
PackedStringArray Node::get_configuration_warnings() const {
ERR_THREAD_GUARD_V(PackedStringArray());
PackedStringArray ret;
@ -3437,10 +3626,6 @@ void Node::update_configuration_warnings() {
#endif
}
bool Node::is_owned_by_parent() const {
return data.parent_owned;
}
void Node::set_display_folded(bool p_folded) {
ERR_THREAD_GUARD
data.display_folded = p_folded;
@ -3568,11 +3753,13 @@ void Node::call_deferred_thread_groupp(const StringName &p_method, const Variant
SceneTree::ProcessGroup *pg = (SceneTree::ProcessGroup *)data.process_group;
pg->call_queue.push_callp(this, p_method, p_args, p_argcount, p_show_error);
}
void Node::set_deferred_thread_group(const StringName &p_property, const Variant &p_value) {
ERR_FAIL_COND(!is_inside_tree());
SceneTree::ProcessGroup *pg = (SceneTree::ProcessGroup *)data.process_group;
pg->call_queue.push_set(this, p_property, p_value);
}
void Node::notify_deferred_thread_group(int p_notification) {
ERR_FAIL_COND(!is_inside_tree());
SceneTree::ProcessGroup *pg = (SceneTree::ProcessGroup *)data.process_group;
@ -3590,6 +3777,7 @@ void Node::call_thread_safep(const StringName &p_method, const Variant **p_args,
call_deferred_thread_groupp(p_method, p_args, p_argcount, p_show_error);
}
}
void Node::set_thread_safe(const StringName &p_property, const Variant &p_value) {
if (is_accessible_from_caller_thread()) {
set(p_property, p_value);
@ -3597,6 +3785,7 @@ void Node::set_thread_safe(const StringName &p_property, const Variant &p_value)
set_deferred_thread_group(p_property, p_value);
}
}
void Node::notify_thread_safe(int p_notification) {
if (is_accessible_from_caller_thread()) {
notification(p_notification);
@ -3605,9 +3794,45 @@ void Node::notify_thread_safe(int p_notification) {
}
}
RID Node::get_focused_accessibility_element() const {
RID id;
if (GDVIRTUAL_CALL(_get_focused_accessibility_element, id)) {
return id;
} else {
return get_accessibility_element();
}
}
String Node::get_accessibility_container_name(const Node *p_node) const {
String ret;
if (GDVIRTUAL_CALL(_get_accessibility_container_name, p_node, ret)) {
} else if (data.parent) {
ret = data.parent->get_accessibility_container_name(this);
}
return ret;
}
void Node::queue_accessibility_update() {
if (is_inside_tree() && !is_part_of_edited_scene()) {
get_tree()->_accessibility_notify_change(this);
}
}
RID Node::get_accessibility_element() const {
if (is_part_of_edited_scene()) {
return RID();
}
if (unlikely(data.accessibility_element.is_null())) {
if (get_window() && get_window()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
data.accessibility_element = DisplayServer::get_singleton()->accessibility_create_element(get_window()->get_window_id(), DisplayServer::ROLE_CONTAINER);
}
}
return data.accessibility_element;
}
void Node::_bind_methods() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"), 0);
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"), NAME_CASING_PASCAL_CASE);
GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/node_name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case,kebab-case"), NAME_CASING_PASCAL_CASE);
ClassDB::bind_static_method("Node", D_METHOD("print_orphan_nodes"), &Node::print_orphan_nodes);
ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false));
@ -3683,6 +3908,24 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_process_thread_group_order", "order"), &Node::set_process_thread_group_order);
ClassDB::bind_method(D_METHOD("get_process_thread_group_order"), &Node::get_process_thread_group_order);
ClassDB::bind_method(D_METHOD("set_accessibility_name", "name"), &Node::set_accessibility_name);
ClassDB::bind_method(D_METHOD("get_accessibility_name"), &Node::get_accessibility_name);
ClassDB::bind_method(D_METHOD("set_accessibility_description", "description"), &Node::set_accessibility_description);
ClassDB::bind_method(D_METHOD("get_accessibility_description"), &Node::get_accessibility_description);
ClassDB::bind_method(D_METHOD("set_accessibility_live", "mode"), &Node::set_accessibility_live);
ClassDB::bind_method(D_METHOD("get_accessibility_live"), &Node::get_accessibility_live);
ClassDB::bind_method(D_METHOD("set_accessibility_controls_nodes", "node_path"), &Node::set_accessibility_controls_nodes);
ClassDB::bind_method(D_METHOD("get_accessibility_controls_nodes"), &Node::get_accessibility_controls_nodes);
ClassDB::bind_method(D_METHOD("set_accessibility_described_by_nodes", "node_path"), &Node::set_accessibility_described_by_nodes);
ClassDB::bind_method(D_METHOD("get_accessibility_described_by_nodes"), &Node::get_accessibility_described_by_nodes);
ClassDB::bind_method(D_METHOD("set_accessibility_labeled_by_nodes", "node_path"), &Node::set_accessibility_labeled_by_nodes);
ClassDB::bind_method(D_METHOD("get_accessibility_labeled_by_nodes"), &Node::get_accessibility_labeled_by_nodes);
ClassDB::bind_method(D_METHOD("set_accessibility_flow_to_nodes", "node_path"), &Node::set_accessibility_flow_to_nodes);
ClassDB::bind_method(D_METHOD("get_accessibility_flow_to_nodes"), &Node::get_accessibility_flow_to_nodes);
ClassDB::bind_method(D_METHOD("queue_accessibility_update"), &Node::queue_accessibility_update);
ClassDB::bind_method(D_METHOD("get_accessibility_element"), &Node::get_accessibility_element);
ClassDB::bind_method(D_METHOD("set_display_folded", "fold"), &Node::set_display_folded);
ClassDB::bind_method(D_METHOD("is_displayed_folded"), &Node::is_displayed_folded);
@ -3756,8 +3999,13 @@ void Node::_bind_methods() {
mi.name = "rpc";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc", &Node::_rpc_bind, mi);
}
mi.arguments.push_front(PropertyInfo(Variant::INT, "peer_id"));
{
MethodInfo mi;
mi.arguments.push_back(PropertyInfo(Variant::INT, "peer_id"));
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
mi.name = "rpc_id";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_id", &Node::_rpc_id_bind, mi);
@ -3820,6 +4068,7 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_WM_DPI_CHANGE);
BIND_CONSTANT(NOTIFICATION_VP_MOUSE_ENTER);
BIND_CONSTANT(NOTIFICATION_VP_MOUSE_EXIT);
BIND_CONSTANT(NOTIFICATION_WM_POSITION_CHANGED);
BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED);
BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
@ -3831,6 +4080,9 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_OUT);
BIND_CONSTANT(NOTIFICATION_TEXT_SERVER_CHANGED);
BIND_CONSTANT(NOTIFICATION_ACCESSIBILITY_UPDATE);
BIND_CONSTANT(NOTIFICATION_ACCESSIBILITY_INVALIDATE);
BIND_ENUM_CONSTANT(PROCESS_MODE_INHERIT);
BIND_ENUM_CONSTANT(PROCESS_MODE_PAUSABLE);
BIND_ENUM_CONSTANT(PROCESS_MODE_WHEN_PAUSED);
@ -3900,16 +4152,28 @@ void Node::_bind_methods() {
ADD_GROUP("Editor Description", "editor_");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT), "set_editor_description", "get_editor_description");
ADD_GROUP("Accessibility", "accessibility_");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "accessibility_name"), "set_accessibility_name", "get_accessibility_name");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "accessibility_description"), "set_accessibility_description", "get_accessibility_description");
ADD_PROPERTY(PropertyInfo(Variant::INT, "accessibility_live", PROPERTY_HINT_ENUM, "Off,Polite,Assertive"), "set_accessibility_live", "get_accessibility_live");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "accessibility_controls_nodes", PROPERTY_HINT_ARRAY_TYPE, "NodePath"), "set_accessibility_controls_nodes", "get_accessibility_controls_nodes");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "accessibility_described_by_nodes", PROPERTY_HINT_ARRAY_TYPE, "NodePath"), "set_accessibility_described_by_nodes", "get_accessibility_described_by_nodes");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "accessibility_labeled_by_nodes", PROPERTY_HINT_ARRAY_TYPE, "NodePath"), "set_accessibility_labeled_by_nodes", "get_accessibility_labeled_by_nodes");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "accessibility_flow_to_nodes", PROPERTY_HINT_ARRAY_TYPE, "NodePath"), "set_accessibility_flow_to_nodes", "get_accessibility_flow_to_nodes");
GDVIRTUAL_BIND(_process, "delta");
GDVIRTUAL_BIND(_physics_process, "delta");
GDVIRTUAL_BIND(_enter_tree);
GDVIRTUAL_BIND(_exit_tree);
GDVIRTUAL_BIND(_ready);
GDVIRTUAL_BIND(_get_configuration_warnings);
GDVIRTUAL_BIND(_get_accessibility_configuration_warnings);
GDVIRTUAL_BIND(_input, "event");
GDVIRTUAL_BIND(_shortcut_input, "event");
GDVIRTUAL_BIND(_unhandled_input, "event");
GDVIRTUAL_BIND(_unhandled_key_input, "event");
GDVIRTUAL_BIND(_get_focused_accessibility_element);
GDVIRTUAL_BIND(_get_accessibility_container_name, "node");
}
String Node::_get_name_num_separator() {
@ -3950,8 +4214,6 @@ Node::Node() {
data.physics_interpolated_client_side = false;
data.use_identity_transform = false;
data.parent_owned = false;
data.in_constructor = true;
data.use_placeholder = false;
data.display_folded = false;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef NODE_H
#define NODE_H
#pragma once
#include "core/string/node_path.h"
#include "core/variant/typed_array.h"
@ -107,7 +106,8 @@ public:
enum NameCasing {
NAME_CASING_PASCAL_CASE,
NAME_CASING_CAMEL_CASE,
NAME_CASING_SNAKE_CASE
NAME_CASING_SNAKE_CASE,
NAME_CASING_KEBAB_CASE,
};
enum InternalMode {
@ -186,6 +186,16 @@ private:
Viewport *viewport = nullptr;
mutable RID accessibility_element;
String accessibility_name;
String accessibility_description;
DisplayServer::AccessibilityLiveMode accessibility_live = DisplayServer::AccessibilityLiveMode::LIVE_OFF;
TypedArray<NodePath> accessibility_controls_nodes;
TypedArray<NodePath> accessibility_described_by_nodes;
TypedArray<NodePath> accessibility_labeled_by_nodes;
TypedArray<NodePath> accessibility_flow_to_nodes;
HashMap<StringName, GroupData> grouped;
List<Node *>::Element *OW = nullptr; // Owned element.
List<Node *> owned;
@ -194,7 +204,7 @@ private:
ProcessThreadGroup process_thread_group = PROCESS_THREAD_GROUP_INHERIT;
Node *process_thread_group_owner = nullptr;
int process_thread_group_order = 0;
BitField<ProcessThreadMessages> process_thread_messages;
BitField<ProcessThreadMessages> process_thread_messages = {};
void *process_group = nullptr; // to avoid cyclic dependency
int multiplayer_authority = 1; // Server by default.
@ -239,8 +249,6 @@ private:
// RenderingServer, and specify the mesh in world space.
bool use_identity_transform : 1;
bool parent_owned : 1;
bool in_constructor : 1;
bool use_placeholder : 1;
bool display_folded : 1;
@ -389,6 +397,7 @@ protected:
GDVIRTUAL0(_enter_tree)
GDVIRTUAL0(_exit_tree)
GDVIRTUAL0(_ready)
GDVIRTUAL0RC(Vector<String>, _get_accessibility_configuration_warnings)
GDVIRTUAL0RC(Vector<String>, _get_configuration_warnings)
GDVIRTUAL1(_input, Ref<InputEvent>)
@ -396,6 +405,9 @@ protected:
GDVIRTUAL1(_unhandled_input, Ref<InputEvent>)
GDVIRTUAL1(_unhandled_key_input, Ref<InputEvent>)
GDVIRTUAL0RC(RID, _get_focused_accessibility_element)
GDVIRTUAL1RC(String, _get_accessibility_container_name, const Node *)
public:
enum {
// You can make your own, but don't use the same numbers as other notifications in other nodes.
@ -421,6 +433,10 @@ public:
NOTIFICATION_ENABLED = 29,
NOTIFICATION_RESET_PHYSICS_INTERPOLATION = 2001, // A GodotSpace Odyssey.
// Keep these linked to Node.
NOTIFICATION_ACCESSIBILITY_UPDATE = 3000,
NOTIFICATION_ACCESSIBILITY_INVALIDATE = 3001,
NOTIFICATION_WM_MOUSE_ENTER = 1002,
NOTIFICATION_WM_MOUSE_EXIT = 1003,
NOTIFICATION_WM_WINDOW_FOCUS_IN = 1004,
@ -487,6 +503,7 @@ public:
}
_FORCE_INLINE_ bool is_inside_tree() const { return data.inside_tree; }
bool is_internal() const { return data.internal_mode != INTERNAL_MODE_DISABLED; }
bool is_ancestor_of(const Node *p_node) const;
bool is_greater_than(const Node *p_node) const;
@ -647,6 +664,36 @@ public:
void set_process_thread_messages(BitField<ProcessThreadMessages> p_flags);
BitField<ProcessThreadMessages> get_process_thread_messages() const;
void set_accessibility_name(const String &p_name);
String get_accessibility_name() const;
void set_accessibility_description(const String &p_description);
String get_accessibility_description() const;
void set_accessibility_live(DisplayServer::AccessibilityLiveMode p_mode);
DisplayServer::AccessibilityLiveMode get_accessibility_live() const;
void set_accessibility_controls_nodes(const TypedArray<NodePath> &p_node_path);
TypedArray<NodePath> get_accessibility_controls_nodes() const;
void set_accessibility_described_by_nodes(const TypedArray<NodePath> &p_node_path);
TypedArray<NodePath> get_accessibility_described_by_nodes() const;
void set_accessibility_labeled_by_nodes(const TypedArray<NodePath> &p_node_path);
TypedArray<NodePath> get_accessibility_labeled_by_nodes() const;
void set_accessibility_flow_to_nodes(const TypedArray<NodePath> &p_node_path);
TypedArray<NodePath> get_accessibility_flow_to_nodes() const;
void queue_accessibility_update();
virtual RID get_accessibility_element() const;
virtual RID get_focused_accessibility_element() const;
virtual String get_accessibility_container_name(const Node *p_node) const;
virtual bool accessibility_override_tree_hierarchy() const { return false; }
virtual PackedStringArray get_accessibility_configuration_warnings() const;
Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
#ifdef TOOLS_ENABLED
Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const;
@ -706,8 +753,6 @@ public:
//hacks for speed
static void init_node_hrcr();
void force_parent_owned() { data.parent_owned = true; } //hack to avoid duplicate nodes
void set_import_path(const NodePath &p_import_path); //path used when imported, used by scene editors to keep tracking
NodePath get_import_path() const;
@ -865,5 +910,3 @@ Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args)
// Add these macro to your class's 'get_configuration_warnings' function to have warnings show up in the scene tree inspector.
#define DEPRECATED_NODE_WARNING warnings.push_back(RTR("This node is marked as deprecated and will be removed in future versions.\nPlease check the Godot documentation for information about migration."));
#define EXPERIMENTAL_NODE_WARNING warnings.push_back(RTR("This node is marked as experimental and may be subject to removal or major changes in future versions."));
#endif // NODE_H

View file

@ -67,9 +67,7 @@ Array ResourcePreloader::_get_resources() const {
i++;
}
Array res;
res.push_back(names);
res.push_back(arr);
Array res = { names, arr };
return res;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef RESOURCE_PRELOADER_H
#define RESOURCE_PRELOADER_H
#pragma once
#include "scene/main/node.h"
@ -56,5 +55,3 @@ public:
ResourcePreloader();
};
#endif // RESOURCE_PRELOADER_H

View file

@ -43,19 +43,26 @@
#include "scene/gui/control.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/viewport.h"
#include "scene/main/window.h"
#include "scene/resources/environment.h"
#include "scene/resources/image_texture.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/world_2d.h"
#include "servers/physics_server_2d.h"
#ifndef _3D_DISABLED
#include "scene/3d/node_3d.h"
#include "scene/resources/3d/world_3d.h"
#include "servers/physics_server_3d.h"
#endif // _3D_DISABLED
#include "window.h"
#ifndef PHYSICS_2D_DISABLED
#include "servers/physics_server_2d.h"
#endif // PHYSICS_2D_DISABLED
#ifndef PHYSICS_3D_DISABLED
#include "servers/physics_server_3d.h"
#endif // PHYSICS_3D_DISABLED
void SceneTreeTimer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left);
@ -130,7 +137,7 @@ void SceneTree::ClientPhysicsInterpolation::physics_process() {
}
}
}
#endif
#endif // _3D_DISABLED
void SceneTree::tree_changed() {
emit_signal(tree_changed_name);
@ -202,6 +209,104 @@ void SceneTree::flush_transform_notifications() {
}
}
bool SceneTree::is_accessibility_enabled() const {
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ACCESSIBILITY_SCREEN_READER)) {
return false;
}
DisplayServer::AccessibilityMode accessibility_mode = DisplayServer::accessibility_get_mode();
int screen_reader_acvite = DisplayServer::get_singleton()->accessibility_screen_reader_active();
if ((accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) || ((accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_AUTO) && (screen_reader_acvite == 0))) {
return false;
}
return true;
}
bool SceneTree::is_accessibility_supported() const {
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ACCESSIBILITY_SCREEN_READER)) {
return false;
}
DisplayServer::AccessibilityMode accessibility_mode = DisplayServer::accessibility_get_mode();
if (accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) {
return false;
}
return true;
}
void SceneTree::_accessibility_force_update() {
accessibility_force_update = true;
}
void SceneTree::_accessibility_notify_change(const Node *p_node, bool p_remove) {
if (p_node) {
if (p_remove) {
accessibility_change_queue.erase(p_node->get_instance_id());
} else {
accessibility_change_queue.insert(p_node->get_instance_id());
}
}
}
void SceneTree::_process_accessibility_changes(DisplayServer::WindowID p_window_id) {
// Process NOTIFICATION_ACCESSIBILITY_UPDATE.
Vector<ObjectID> processed;
for (const ObjectID &id : accessibility_change_queue) {
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id));
if (!node || !node->get_window()) {
processed.push_back(id);
continue; // Invalid node, remove from list and skip.
} else if (node->get_window()->get_window_id() != p_window_id) {
continue; // Another window, skip.
}
node->notification(Node::NOTIFICATION_ACCESSIBILITY_UPDATE);
processed.push_back(id);
}
// Track focus change.
// Note: Do not use `Window::get_focused_window()`, it returns both native and embedded windows, and we only care about focused element in the currently processed native window.
// Native window focus is handled in the DisplayServer, or AccessKit subclassing adapter.
ObjectID oid = DisplayServer::get_singleton()->window_get_attached_instance_id(p_window_id);
Window *w_this = (Window *)ObjectDB::get_instance(oid);
if (w_this) {
Window *w_focus = w_this->get_focused_subwindow();
if (w_focus && !w_focus->is_part_of_edited_scene()) {
w_this = w_focus;
}
RID new_focus_element;
Control *n_focus = w_this->gui_get_focus_owner();
if (n_focus && !n_focus->is_part_of_edited_scene()) {
new_focus_element = n_focus->get_focused_accessibility_element();
} else {
new_focus_element = w_this->get_focused_accessibility_element();
}
DisplayServer::get_singleton()->accessibility_update_set_focus(new_focus_element);
}
// Cleanup.
for (const ObjectID &id : processed) {
accessibility_change_queue.erase(id);
}
}
void SceneTree::_flush_accessibility_changes() {
if (is_accessibility_enabled()) {
uint64_t time = OS::get_singleton()->get_ticks_msec();
if (!accessibility_force_update) {
if (time - accessibility_last_update < 1000 / accessibility_upd_per_sec) {
return;
}
}
accessibility_force_update = false;
accessibility_last_update = time;
// Push update to the accessibility driver.
DisplayServer::get_singleton()->accessibility_update_if_active(callable_mp(this, &SceneTree::_process_accessibility_changes));
}
}
void SceneTree::_flush_ugc() {
ugc_locked = true;
@ -526,7 +631,9 @@ bool SceneTree::physics_process(double p_time) {
emit_signal(SNAME("physics_frame"));
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
call_group(SNAME("_picking_viewports"), SNAME("_process_picking"));
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
_process(true);
@ -540,6 +647,7 @@ bool SceneTree::physics_process(double p_time) {
// This should happen last because any processing that deletes something beforehand might expect the object to be removed in the same frame.
_flush_delete_queue();
_call_idle_callbacks();
return _quit;
@ -586,7 +694,7 @@ bool SceneTree::process(double p_time) {
MessageQueue::get_singleton()->flush(); //small little hack
flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications
if (unlikely(pending_new_scene)) {
if (unlikely(pending_new_scene_id.is_valid())) {
_flush_scene_change();
}
@ -598,6 +706,8 @@ bool SceneTree::process(double p_time) {
// This should happen last because any processing that deletes something beforehand might expect the object to be removed in the same frame.
_flush_delete_queue();
_flush_accessibility_changes();
_call_idle_callbacks();
#ifdef TOOLS_ENABLED
@ -769,9 +879,7 @@ void SceneTree::_main_window_focus_in() {
void SceneTree::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_TRANSLATION_CHANGED: {
if (!Engine::get_singleton()->is_editor_hint()) {
get_root()->propagate_notification(p_notification);
}
get_root()->propagate_notification(p_notification);
} break;
case NOTIFICATION_OS_MEMORY_WARNING:
@ -972,10 +1080,12 @@ void SceneTree::set_pause(bool p_enabled) {
paused = p_enabled;
#ifndef _3D_DISABLED
#ifndef PHYSICS_3D_DISABLED
PhysicsServer3D::get_singleton()->set_active(!p_enabled);
#endif // _3D_DISABLED
#endif // PHYSICS_3D_DISABLED
#ifndef PHYSICS_2D_DISABLED
PhysicsServer2D::get_singleton()->set_active(!p_enabled);
#endif // PHYSICS_2D_DISABLED
if (get_root()) {
get_root()->_propagate_pause_notification(p_enabled);
}
@ -996,10 +1106,12 @@ void SceneTree::set_suspend(bool p_enabled) {
Engine::get_singleton()->set_freeze_time_scale(p_enabled);
#ifndef _3D_DISABLED
#ifndef PHYSICS_3D_DISABLED
PhysicsServer3D::get_singleton()->set_active(!p_enabled && !paused);
#endif // _3D_DISABLED
#endif // PHYSICS_3D_DISABLED
#ifndef PHYSICS_2D_DISABLED
PhysicsServer2D::get_singleton()->set_active(!p_enabled && !paused);
#endif // PHYSICS_2D_DISABLED
if (get_root()) {
get_root()->_propagate_suspend_notification(p_enabled);
}
@ -1340,7 +1452,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
if (p_viewport->is_input_handled()) {
break;
}
Node *n = Object::cast_to<Node>(ObjectDB::get_instance(id));
Node *n = ObjectDB::get_instance<Node>(id);
if (n) {
n->_call_shortcut_input(p_input);
}
@ -1508,15 +1620,33 @@ Node *SceneTree::get_current_scene() const {
}
void SceneTree::_flush_scene_change() {
if (prev_scene) {
memdelete(prev_scene);
prev_scene = nullptr;
if (prev_scene_id.is_valid()) {
// Might have already been freed externally.
Node *prev_scene = ObjectDB::get_instance<Node>(prev_scene_id);
if (prev_scene) {
memdelete(prev_scene);
}
prev_scene_id = ObjectID();
}
DEV_ASSERT(pending_new_scene_id.is_valid());
Node *pending_new_scene = ObjectDB::get_instance<Node>(pending_new_scene_id);
if (pending_new_scene) {
// Ensure correct state before `add_child` (might enqueue subsequent scene change).
current_scene = pending_new_scene;
pending_new_scene_id = ObjectID();
root->add_child(pending_new_scene);
// Update display for cursor instantly.
root->update_mouse_cursor_state();
// Only on successful scene change.
emit_signal(SNAME("scene_changed"));
} else {
current_scene = nullptr;
pending_new_scene_id = ObjectID();
ERR_PRINT("Scene instance has been freed before becoming the current scene. No current scene is set.");
}
current_scene = pending_new_scene;
root->add_child(pending_new_scene);
pending_new_scene = nullptr;
// Update display for cursor instantly.
root->update_mouse_cursor_state();
}
Error SceneTree::change_scene_to_file(const String &p_path) {
@ -1536,21 +1666,23 @@ Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) {
ERR_FAIL_NULL_V(new_scene, ERR_CANT_CREATE);
// If called again while a change is pending.
if (pending_new_scene) {
queue_delete(pending_new_scene);
pending_new_scene = nullptr;
if (pending_new_scene_id.is_valid()) {
Node *pending_new_scene = ObjectDB::get_instance<Node>(pending_new_scene_id);
if (pending_new_scene) {
queue_delete(pending_new_scene);
}
pending_new_scene_id = ObjectID();
}
prev_scene = current_scene;
if (current_scene) {
prev_scene_id = current_scene->get_instance_id();
// Let as many side effects as possible happen or be queued now,
// so they are run before the scene is actually deleted.
root->remove_child(current_scene);
}
DEV_ASSERT(!current_scene);
pending_new_scene = new_scene;
pending_new_scene_id = new_scene->get_instance_id();
return OK;
}
@ -1701,6 +1833,9 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root"), &SceneTree::get_root);
ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);
ClassDB::bind_method(D_METHOD("is_accessibility_enabled"), &SceneTree::is_accessibility_enabled);
ClassDB::bind_method(D_METHOD("is_accessibility_supported"), &SceneTree::is_accessibility_supported);
ClassDB::bind_method(D_METHOD("is_auto_accept_quit"), &SceneTree::is_auto_accept_quit);
ClassDB::bind_method(D_METHOD("set_auto_accept_quit", "enabled"), &SceneTree::set_auto_accept_quit);
ClassDB::bind_method(D_METHOD("is_quit_on_go_back"), &SceneTree::is_quit_on_go_back);
@ -1784,6 +1919,7 @@ void SceneTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_interpolation"), "set_physics_interpolation_enabled", "is_physics_interpolation_enabled");
ADD_SIGNAL(MethodInfo("tree_changed"));
ADD_SIGNAL(MethodInfo("scene_changed"));
ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it can't be removed in run-time
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
@ -1847,6 +1983,7 @@ SceneTree::SceneTree() {
debug_paths_color = GLOBAL_DEF("debug/shapes/paths/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_paths_width = GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "debug/shapes/paths/geometry_width", PROPERTY_HINT_RANGE, "0.01,10,0.001,or_greater"), 2.0);
collision_debug_contacts = GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1"), 10000);
accessibility_upd_per_sec = GLOBAL_GET(SNAME("accessibility/general/updates_per_second"));
GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
@ -1992,7 +2129,9 @@ SceneTree::SceneTree() {
}
#endif // _3D_DISABLED
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true));
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
root->connect("close_requested", callable_mp(this, &SceneTree::_main_window_close));
root->connect("go_back_requested", callable_mp(this, &SceneTree::_main_window_go_back));
@ -2006,13 +2145,19 @@ SceneTree::SceneTree() {
}
SceneTree::~SceneTree() {
if (prev_scene) {
memdelete(prev_scene);
prev_scene = nullptr;
if (prev_scene_id.is_valid()) {
Node *prev_scene = ObjectDB::get_instance<Node>(prev_scene_id);
if (prev_scene) {
memdelete(prev_scene);
}
prev_scene_id = ObjectID();
}
if (pending_new_scene) {
memdelete(pending_new_scene);
pending_new_scene = nullptr;
if (pending_new_scene_id.is_valid()) {
Node *pending_new_scene = ObjectDB::get_instance<Node>(pending_new_scene_id);
if (pending_new_scene) {
memdelete(pending_new_scene);
}
pending_new_scene_id = ObjectID();
}
if (root) {
root->_set_tree(nullptr);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SCENE_TREE_H
#define SCENE_TREE_H
#pragma once
#include "core/os/main_loop.h"
#include "core/os/thread_safe.h"
@ -179,6 +178,11 @@ private:
List<ObjectID> delete_queue;
uint64_t accessibility_upd_per_sec = 0;
bool accessibility_force_update = true;
HashSet<ObjectID> accessibility_change_queue;
uint64_t accessibility_last_update = 0;
HashMap<UGCall, Vector<Variant>, UGCall> unique_group_calls;
bool ugc_locked = false;
void _flush_ugc();
@ -188,8 +192,8 @@ private:
TypedArray<Node> _get_nodes_in_group(const StringName &p_group);
Node *current_scene = nullptr;
Node *prev_scene = nullptr;
Node *pending_new_scene = nullptr;
ObjectID prev_scene_id;
ObjectID pending_new_scene_id;
Color debug_collisions_color;
Color debug_collision_contact_color;
@ -321,6 +325,13 @@ public:
void flush_transform_notifications();
bool is_accessibility_enabled() const;
bool is_accessibility_supported() const;
void _accessibility_force_update();
void _accessibility_notify_change(const Node *p_node, bool p_remove = false);
void _flush_accessibility_changes();
void _process_accessibility_changes(DisplayServer::WindowID p_window_id);
virtual void initialize() override;
virtual void iteration_prepare() override;
@ -448,5 +459,3 @@ public:
};
VARIANT_ENUM_CAST(SceneTree::GroupCallFlags);
#endif // SCENE_TREE_H

View file

@ -228,7 +228,7 @@ void ShaderGlobalsOverride::_activate() {
ERR_FAIL_NULL(get_tree());
List<Node *> nodes;
get_tree()->get_nodes_in_group(SceneStringName(shader_overrides_group_active), &nodes);
if (nodes.size() == 0) {
if (nodes.is_empty()) {
//good we are the only override, enable all
active = true;
add_to_group(SceneStringName(shader_overrides_group_active));

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SHADER_GLOBALS_OVERRIDE_H
#define SHADER_GLOBALS_OVERRIDE_H
#pragma once
#include "scene/main/node.h"
@ -62,5 +61,3 @@ public:
ShaderGlobalsOverride();
};
#endif // SHADER_GLOBALS_OVERRIDE_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef STATUS_INDICATOR_H
#define STATUS_INDICATOR_H
#pragma once
#include "scene/main/node.h"
#include "servers/display_server.h"
@ -64,5 +63,3 @@ public:
Rect2 get_rect() const;
};
#endif // STATUS_INDICATOR_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef TIMER_H
#define TIMER_H
#pragma once
#include "scene/main/node.h"
@ -89,5 +88,3 @@ private:
};
VARIANT_ENUM_CAST(Timer::TimerProcessCallback);
#endif // TIMER_H

View file

@ -36,13 +36,6 @@
#include "core/templates/sort_array.h"
#include "scene/2d/audio_listener_2d.h"
#include "scene/2d/camera_2d.h"
#include "scene/2d/physics/collision_object_2d.h"
#ifndef _3D_DISABLED
#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/physics/collision_object_3d.h"
#include "scene/3d/world_environment.h"
#endif // _3D_DISABLED
#include "scene/gui/control.h"
#include "scene/gui/label.h"
#include "scene/gui/popup.h"
@ -56,6 +49,20 @@
#include "servers/audio_server.h"
#include "servers/rendering/rendering_server_globals.h"
#ifndef _3D_DISABLED
#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/world_environment.h"
#endif // _3D_DISABLED
#ifndef PHYSICS_2D_DISABLED
#include "scene/2d/physics/collision_object_2d.h"
#endif // PHYSICS_2D_DISABLED
#ifndef PHYSICS_3D_DISABLED
#include "scene/3d/physics/collision_object_3d.h"
#endif // PHYSICS_3D_DISABLED
void ViewportTexture::setup_local_to_scene() {
// For the same target viewport, setup is only allowed once to prevent multiple free or multiple creations.
if (!vp_changed) {
@ -287,7 +294,7 @@ void Viewport::_sub_window_register(Window *p_window) {
ERR_FAIL_COND(gui.sub_windows[i].window == p_window);
}
if (gui.sub_windows.size() == 0) {
if (gui.sub_windows.is_empty()) {
subwindow_canvas = RS::get_singleton()->canvas_create();
RS::get_singleton()->viewport_attach_canvas(viewport, subwindow_canvas);
RS::get_singleton()->viewport_set_canvas_stacking(viewport, subwindow_canvas, SUBWINDOW_CANVAS_LAYER, 0);
@ -317,7 +324,13 @@ void Viewport::_sub_window_register(Window *p_window) {
void Viewport::_sub_window_update(Window *p_window) {
int index = _sub_window_find(p_window);
ERR_FAIL_COND(index == -1);
// _sub_window_update is sometimes called deferred, and the window may have been closed since then.
// For example, when the user resizes the game window.
// In that case, _sub_window_find will not find it, which is expected.
if (index == -1) {
return;
}
SubWindow &sw = gui.sub_windows.write[index];
sw.pending_window_update = false;
@ -452,7 +465,7 @@ void Viewport::_sub_window_remove(Window *p_window) {
RS::get_singleton()->free(sw.canvas_item);
gui.sub_windows.remove_at(index);
if (gui.sub_windows.size() == 0) {
if (gui.sub_windows.is_empty()) {
RS::get_singleton()->free(subwindow_canvas);
subwindow_canvas = RID();
}
@ -502,18 +515,14 @@ int Viewport::_sub_window_find(Window *p_window) const {
}
void Viewport::_update_viewport_path() {
if (viewport_textures.is_empty()) {
if (!is_inside_tree()) {
return;
}
Node *scene_root = get_scene_file_path().is_empty() ? get_owner() : this;
if (!scene_root && is_inside_tree()) {
scene_root = get_tree()->get_edited_scene_root();
}
if (scene_root && (scene_root == this || scene_root->is_ancestor_of(this))) {
NodePath path_in_scene = scene_root->get_path_to(this);
for (ViewportTexture *E : viewport_textures) {
E->path = path_in_scene;
for (ViewportTexture *E : viewport_textures) {
Node *loc_scene = E->get_local_scene();
if (loc_scene) {
E->path = loc_scene->get_path_to(this);
}
}
}
@ -543,11 +552,14 @@ void Viewport::_notification(int p_what) {
#endif // _3D_DISABLED
add_to_group("_viewports");
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
if (get_tree()->is_debugging_collisions_hint()) {
#ifndef PHYSICS_2D_DISABLED
PhysicsServer2D::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count());
contact_2d_debug = RenderingServer::get_singleton()->canvas_item_create();
RenderingServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, current_canvas);
#ifndef _3D_DISABLED
#endif // PHYSICS_2D_DISABLED
#ifndef PHYSICS_3D_DISABLED
PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world_3d()->get_space(), get_tree()->get_collision_debug_contact_count());
contact_3d_debug_multimesh = RenderingServer::get_singleton()->multimesh_create();
RenderingServer::get_singleton()->multimesh_allocate_data(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, false);
@ -557,9 +569,10 @@ void Viewport::_notification(int p_what) {
RenderingServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh);
RenderingServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world_3d()->get_scenario());
RenderingServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
#endif // _3D_DISABLED
#endif // PHYSICS_3D_DISABLED
set_physics_process_internal(true);
}
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
} break;
case NOTIFICATION_READY: {
@ -598,17 +611,21 @@ void Viewport::_notification(int p_what) {
RenderingServer::get_singleton()->viewport_set_scenario(viewport, RID());
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
#ifndef PHYSICS_2D_DISABLED
if (contact_2d_debug.is_valid()) {
RenderingServer::get_singleton()->free(contact_2d_debug);
contact_2d_debug = RID();
}
#endif // PHYSICS_2D_DISABLED
#ifndef PHYSICS_3D_DISABLED
if (contact_3d_debug_multimesh.is_valid()) {
RenderingServer::get_singleton()->free(contact_3d_debug_multimesh);
RenderingServer::get_singleton()->free(contact_3d_debug_instance);
contact_3d_debug_instance = RID();
contact_3d_debug_multimesh = RID();
}
#endif // PHYSICS_3D_DISABLED
remove_from_group("_viewports");
set_physics_process_internal(false);
@ -621,11 +638,13 @@ void Viewport::_notification(int p_what) {
_update_viewport_path();
} break;
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (!get_tree()) {
return;
}
#ifndef PHYSICS_2D_DISABLED
if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) {
RenderingServer::get_singleton()->canvas_item_clear(contact_2d_debug);
RenderingServer::get_singleton()->canvas_item_set_draw_index(contact_2d_debug, 0xFFFFF); //very high index
@ -638,7 +657,8 @@ void Viewport::_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol);
}
}
#ifndef _3D_DISABLED
#endif // PHYSICS_2D_DISABLED
#ifndef PHYSICS_3D_DISABLED
if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) {
Vector<Vector3> points = PhysicsServer3D::get_singleton()->space_get_contacts(find_world_3d()->get_space());
int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world_3d()->get_space());
@ -651,8 +671,9 @@ void Viewport::_notification(int p_what) {
RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform);
}
}
#endif // _3D_DISABLED
#endif // PHYSICS_3D_DISABLED
} break;
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
case NOTIFICATION_VP_MOUSE_ENTER: {
gui.mouse_in_viewport = true;
@ -685,6 +706,7 @@ void Viewport::_notification(int p_what) {
}
}
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
void Viewport::_process_picking() {
if (!is_inside_tree()) {
return;
@ -701,7 +723,7 @@ void Viewport::_process_picking() {
physics_picking_events.clear();
return;
}
#ifndef _3D_DISABLED
#ifndef XR_DISABLED
if (use_xr) {
if (XRServer::get_singleton() != nullptr) {
Ref<XRInterface> xr_interface = XRServer::get_singleton()->get_primary_interface();
@ -712,21 +734,23 @@ void Viewport::_process_picking() {
}
}
}
#endif
#endif // XR_DISABLED
_drop_physics_mouseover(true);
#ifndef _3D_DISABLED
#ifndef PHYSICS_3D_DISABLED
Vector2 last_pos(1e20, 1e20);
CollisionObject3D *last_object = nullptr;
ObjectID last_id;
PhysicsDirectSpaceState3D::RayResult result;
#endif // _3D_DISABLED
#endif // PHYSICS_3D_DISABLED
#ifndef PHYSICS_2D_DISABLED
PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
#endif // PHYSICS_2D_DISABLED
SubViewportContainer *parent_svc = Object::cast_to<SubViewportContainer>(get_parent());
bool parent_ignore_mouse = (parent_svc && parent_svc->get_mouse_filter() == Control::MOUSE_FILTER_IGNORE);
bool parent_ignore_mouse = (parent_svc && parent_svc->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_IGNORE);
bool create_passive_hover_event = true;
if (gui.mouse_over || parent_ignore_mouse) {
// When the mouse is over a Control node, passive hovering would cause input events for Colliders, that are behind Control nodes.
@ -803,6 +827,7 @@ void Viewport::_process_picking() {
pos = st->get_position();
}
#ifndef PHYSICS_2D_DISABLED
if (ss2d) {
// Send to 2D.
@ -895,15 +920,16 @@ void Viewport::_process_picking() {
_cleanup_mouseover_colliders(false, false, frame);
}
}
#endif // PHYSICS_2D_DISABLED
#ifndef _3D_DISABLED
#ifndef PHYSICS_3D_DISABLED
if (physics_object_picking_first_only && is_input_handled()) {
continue;
}
CollisionObject3D *capture_object = nullptr;
if (physics_object_capture.is_valid()) {
capture_object = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture));
capture_object = ObjectDB::get_instance<CollisionObject3D>(physics_object_capture);
if (!capture_object || !camera_3d || (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed())) {
physics_object_capture = ObjectID();
} else {
@ -952,7 +978,7 @@ void Viewport::_process_picking() {
if (is_mouse && new_collider != physics_object_over) {
if (physics_object_over.is_valid()) {
CollisionObject3D *previous_co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
CollisionObject3D *previous_co = ObjectDB::get_instance<CollisionObject3D>(physics_object_over);
if (previous_co) {
previous_co->_mouse_exit();
}
@ -975,9 +1001,10 @@ void Viewport::_process_picking() {
last_pos = pos;
}
}
#endif // _3D_DISABLED
#endif // PHYSICS_3D_DISABLED
}
}
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
RID Viewport::get_viewport_rid() const {
ERR_READ_THREAD_GUARD_V(RID());
@ -1002,10 +1029,10 @@ void Viewport::update_canvas_items() {
_update_canvas_items(this);
}
bool Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, bool p_allocated) {
bool Viewport::_set_size(const Size2i &p_size, const Size2 &p_size_2d_override, bool p_allocated) {
Transform2D stretch_transform_new = Transform2D();
if (is_size_2d_override_stretch_enabled() && p_size_2d_override.width > 0 && p_size_2d_override.height > 0) {
Size2 scale = Size2(p_size) / Size2(p_size_2d_override);
Size2 scale = Size2(p_size) / p_size_2d_override;
stretch_transform_new.scale(scale);
}
@ -1058,7 +1085,7 @@ bool Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
}
Size2i Viewport::_get_size() const {
#ifndef _3D_DISABLED
#ifndef XR_DISABLED
if (use_xr) {
if (XRServer::get_singleton() != nullptr) {
Ref<XRInterface> xr_interface = XRServer::get_singleton()->get_primary_interface();
@ -1069,12 +1096,12 @@ Size2i Viewport::_get_size() const {
}
return Size2i();
}
#endif // _3D_DISABLED
#endif // XR_DISABLED
return size;
}
Size2i Viewport::_get_size_2d_override() const {
Size2 Viewport::_get_size_2d_override() const {
return size_2d_override;
}
@ -1092,7 +1119,7 @@ Rect2 Viewport::get_visible_rect() const {
r = Rect2(Point2(), size);
}
if (size_2d_override != Size2i()) {
if (size_2d_override != Size2()) {
r.size = size_2d_override;
}
@ -1488,7 +1515,28 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont
return tooltip;
}
void Viewport::cancel_tooltip() {
_gui_cancel_tooltip();
}
void Viewport::show_tooltip(Control *p_control) {
if (!p_control) {
return;
}
if (gui.tooltip_timer.is_valid()) {
gui.tooltip_timer->release_connections();
gui.tooltip_timer = Ref<SceneTreeTimer>();
}
gui.tooltip_control = p_control;
_gui_show_tooltip_at(p_control->get_size() / 2);
}
void Viewport::_gui_show_tooltip() {
_gui_show_tooltip_at(gui.last_mouse_pos);
}
void Viewport::_gui_show_tooltip_at(const Point2i &p_pos) {
if (!gui.tooltip_control) {
return;
}
@ -1509,6 +1557,7 @@ void Viewport::_gui_show_tooltip() {
// This way, the custom tooltip from `ConnectionsDockTree` can create
// its own tooltip without conflicting with the default one, even an empty tooltip.
if (base_tooltip && !base_tooltip->is_visible()) {
memdelete(base_tooltip);
return;
}
@ -1546,6 +1595,8 @@ void Viewport::_gui_show_tooltip() {
panel->set_flag(Window::FLAG_POPUP, false);
panel->set_flag(Window::FLAG_MOUSE_PASSTHROUGH, true);
panel->set_wrap_controls(true);
panel->set_default_canvas_item_texture_filter(get_default_canvas_item_texture_filter());
panel->set_default_canvas_item_texture_repeat(get_default_canvas_item_texture_repeat());
panel->add_child(base_tooltip);
panel->gui_parent = this;
@ -1557,20 +1608,19 @@ void Viewport::_gui_show_tooltip() {
if (!window) { // Not embedded.
window = gui.tooltip_popup->get_parent_visible_window();
}
float win_scale = window->content_scale_factor;
Size2 scale = get_popup_base_transform().get_scale();
real_t popup_scale = MIN(scale.x, scale.y);
Point2 tooltip_offset = GLOBAL_GET("display/mouse_cursor/tooltip_position_offset");
if (!gui.tooltip_popup->is_embedded()) {
tooltip_offset *= win_scale;
}
tooltip_offset *= popup_scale;
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size());
Rect2i vr;
if (gui.tooltip_popup->is_embedded()) {
vr = gui.tooltip_popup->get_embedder()->get_visible_rect();
} else {
panel->content_scale_factor = win_scale;
r.size *= win_scale;
vr = window->get_usable_parent_rect();
}
panel->content_scale_factor = popup_scale;
r.size *= popup_scale;
r.size = r.size.ceil();
r.size = r.size.min(panel->get_max_size());
@ -1822,9 +1872,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
#ifdef DEBUG_ENABLED
if (EngineDebugger::get_singleton()) {
Array arr;
arr.push_back(gui.mouse_focus->get_path());
arr.push_back(gui.mouse_focus->get_class());
Array arr = { gui.mouse_focus->get_path(), gui.mouse_focus->get_class() };
EngineDebugger::get_singleton()->send_message("scene:click_ctrl", arr);
}
#endif
@ -1834,7 +1882,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
while (ci) {
Control *control = Object::cast_to<Control>(ci);
if (control) {
if (control->get_focus_mode() != Control::FOCUS_NONE) {
if (control->get_focus_mode_with_recursive() != Control::FOCUS_NONE) {
// Grabbing unhovered focus can cause issues when mouse is dragged
// with another button held down.
if (control != gui.key_focus && gui.mouse_over_hierarchy.has(control)) {
@ -2085,7 +2133,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
} else {
ObjectID control_id = gui.touch_focus[touch_index];
Control *over = control_id.is_valid() ? Object::cast_to<Control>(ObjectDB::get_instance(control_id)) : nullptr;
Control *over = control_id.is_valid() ? ObjectDB::get_instance<Control>(control_id) : nullptr;
if (over && over->can_process()) {
touch_event = touch_event->xformed_by(Transform2D()); // Make a copy.
pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
@ -2120,7 +2168,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (drag_event.is_valid()) {
const int drag_event_index = drag_event->get_index();
ObjectID control_id = gui.touch_focus[drag_event_index];
Control *over = control_id.is_valid() ? Object::cast_to<Control>(ObjectDB::get_instance(control_id)) : nullptr;
Control *over = control_id.is_valid() ? ObjectDB::get_instance<Control>(control_id) : nullptr;
if (!over) {
over = gui_find_control(drag_event->get_position());
}
@ -2178,6 +2226,17 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
Control *from = gui.key_focus ? gui.key_focus : nullptr;
if (!from) {
for (int i = 0; i < get_child_count(true); i++) {
Control *c = Object::cast_to<Control>(get_child(i, true));
if (!c || !c->is_visible_in_tree() || c->is_set_as_top_level()) {
continue;
}
from = c;
break;
}
}
if (from && p_event->is_pressed()) {
Control *next = nullptr;
@ -2194,6 +2253,14 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
next = from->find_prev_valid_focus();
}
if (p_event->is_action_pressed(SNAME("ui_accessibility_drag_and_drop")) && input->is_action_just_pressed(SNAME("ui_accessibility_drag_and_drop"))) {
if (gui_is_dragging()) {
from->accessibility_drop();
} else {
from->accessibility_drag();
}
}
if (p_event->is_action_pressed(SNAME("ui_up")) && input->is_action_just_pressed(SNAME("ui_up"))) {
next = from->_get_focus_neighbor(SIDE_TOP);
}
@ -2218,6 +2285,14 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
next = from->find_prev_valid_focus();
}
if (p_event->is_action_pressed(SNAME("ui_accessibility_drag_and_drop"), true, true)) {
if (gui_is_dragging()) {
from->accessibility_drop();
} else {
from->accessibility_drag();
}
}
if (p_event->is_action_pressed(SNAME("ui_up"), true, true)) {
next = from->_get_focus_neighbor(SIDE_TOP);
}
@ -2243,9 +2318,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
void Viewport::_perform_drop(Control *p_control) {
gui_perform_drop_at(p_control ? p_control->get_local_mouse_position() : Vector2(), p_control);
}
void Viewport::gui_perform_drop_at(const Point2 &p_pos, Control *p_control) {
// Without any arguments, simply cancel Drag and Drop.
if (p_control) {
gui.drag_successful = _gui_drop(p_control, p_control->get_local_mouse_position(), false);
gui.drag_successful = _gui_drop(p_control, p_pos, false);
} else {
gui.drag_successful = false;
}
@ -2259,6 +2338,7 @@ void Viewport::_perform_drop(Control *p_control) {
Viewport *section_root = get_section_root_viewport();
section_root->gui.drag_data = Variant();
gui.dragging = false;
gui.drag_description = String();
section_root->gui.global_dragging = false;
gui.drag_mouse_over = nullptr;
Viewport::_propagate_drag_notification(section_root, NOTIFICATION_DRAG_END);
@ -2287,12 +2367,23 @@ void Viewport::gui_set_root_order_dirty() {
gui.roots_order_dirty = true;
}
void Viewport::_gui_force_drag_start() {
Viewport *section_root = get_section_root_viewport();
section_root->gui.global_dragging = true;
}
void Viewport::_gui_force_drag_cancel() {
Viewport *section_root = get_section_root_viewport();
section_root->gui.global_dragging = false;
}
void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control) {
ERR_FAIL_COND_MSG(p_data.get_type() == Variant::NIL, "Drag data must be a value.");
gui.dragging = true;
Viewport *section_root = get_section_root_viewport();
section_root->gui.global_dragging = true;
ERR_FAIL_COND(!section_root->gui.global_dragging);
gui.dragging = true;
section_root->gui.drag_data = p_data;
gui.mouse_focus = nullptr;
gui.mouse_focus_mask.clear();
@ -2324,7 +2415,7 @@ Control *Viewport::_gui_get_drag_preview() {
if (gui.drag_preview_id.is_null()) {
return nullptr;
} else {
Control *drag_preview = Object::cast_to<Control>(ObjectDB::get_instance(gui.drag_preview_id));
Control *drag_preview = ObjectDB::get_instance<Control>(gui.drag_preview_id);
if (!drag_preview) {
ERR_PRINT("Don't free the control set as drag preview.");
gui.drag_preview_id = ObjectID();
@ -2412,7 +2503,7 @@ void Viewport::_gui_update_mouse_over() {
int found = gui.mouse_over_hierarchy.find(ancestor_control);
if (found >= 0) {
// Remove the node if the propagation chain has been broken or it is now MOUSE_FILTER_IGNORE.
if (removing || ancestor_control->get_mouse_filter() == Control::MOUSE_FILTER_IGNORE) {
if (removing || ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_IGNORE) {
needs_exit.push_back(found);
}
}
@ -2423,14 +2514,14 @@ void Viewport::_gui_update_mouse_over() {
}
reached_top = true;
}
if (!removing && ancestor_control->get_mouse_filter() != Control::MOUSE_FILTER_IGNORE) {
if (!removing && ancestor_control->get_mouse_filter_with_recursive() != Control::MOUSE_FILTER_IGNORE) {
new_mouse_over_hierarchy.push_back(ancestor_control);
// Add the node if it was not found and it is now not MOUSE_FILTER_IGNORE.
if (found < 0) {
needs_enter.push_back(ancestor_control);
}
}
if (ancestor_control->get_mouse_filter() == Control::MOUSE_FILTER_STOP) {
if (ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_STOP) {
// MOUSE_FILTER_STOP breaks the propagation chain.
if (reached_top) {
break;
@ -2550,11 +2641,13 @@ void Viewport::_drop_mouse_focus() {
}
void Viewport::_drop_physics_mouseover(bool p_paused_only) {
#ifndef PHYSICS_2D_DISABLED
_cleanup_mouseover_colliders(true, p_paused_only);
#endif // PHYSICS_2D_DISABLED
#ifndef _3D_DISABLED
#ifndef PHYSICS_3D_DISABLED
if (physics_object_over.is_valid()) {
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
CollisionObject3D *co = ObjectDB::get_instance<CollisionObject3D>(physics_object_over);
if (co) {
if (!co->is_inside_tree()) {
physics_object_over = ObjectID();
@ -2566,7 +2659,7 @@ void Viewport::_drop_physics_mouseover(bool p_paused_only) {
}
}
}
#endif // _3D_DISABLED
#endif // PHYSICS_3D_DISABLED
}
void Viewport::_gui_grab_click_focus(Control *p_control) {
@ -2660,11 +2753,11 @@ Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subw
int limit = p_subwindow->theme_cache.resize_margin;
if (ABS(dist_x) > limit) {
if (Math::abs(dist_x) > limit) {
return SUB_WINDOW_RESIZE_DISABLED;
}
if (ABS(dist_y) > limit) {
if (Math::abs(dist_y) > limit) {
return SUB_WINDOW_RESIZE_DISABLED;
}
@ -3089,7 +3182,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
while (ancestor) {
Control *ancestor_control = Object::cast_to<Control>(ancestor);
if (ancestor_control) {
if (ancestor_control->get_mouse_filter() != Control::MOUSE_FILTER_IGNORE) {
if (ancestor_control->get_mouse_filter_with_recursive() != Control::MOUSE_FILTER_IGNORE) {
int found = gui.mouse_over_hierarchy.find(ancestor_control);
if (found >= 0) {
common_ancestor = gui.mouse_over_hierarchy[found];
@ -3097,7 +3190,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
}
over_ancestors.push_back(ancestor_control);
}
if (ancestor_control->get_mouse_filter() == Control::MOUSE_FILTER_STOP) {
if (ancestor_control->get_mouse_filter_with_recursive() == Control::MOUSE_FILTER_STOP) {
// MOUSE_FILTER_STOP breaks the propagation chain.
break;
}
@ -3339,6 +3432,7 @@ void Viewport::_push_unhandled_input_internal(const Ref<InputEvent> &p_event) {
get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, p_event, this);
}
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
if (physics_object_picking && !is_input_handled()) {
if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED &&
(Object::cast_to<InputEventMouse>(*p_event) ||
@ -3350,6 +3444,7 @@ void Viewport::_push_unhandled_input_internal(const Ref<InputEvent> &p_event) {
set_input_as_handled();
}
}
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
}
void Viewport::notify_mouse_entered() {
@ -3368,6 +3463,7 @@ void Viewport::notify_mouse_exited() {
_mouse_leave_viewport();
}
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
void Viewport::set_physics_object_picking(bool p_enable) {
ERR_MAIN_THREAD_GUARD;
physics_object_picking = p_enable;
@ -3403,6 +3499,7 @@ void Viewport::set_physics_object_picking_first_only(bool p_enable) {
bool Viewport::get_physics_object_picking_first_only() {
return physics_object_picking_first_only;
}
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
ERR_READ_THREAD_GUARD_V(Vector2());
@ -3446,6 +3543,19 @@ void Viewport::set_disable_input_override(bool p_disable) {
disable_input_override = p_disable;
}
String Viewport::gui_get_drag_description() const {
ERR_READ_THREAD_GUARD_V(String());
if (get_section_root_viewport()->gui.drag_description.is_empty()) {
return RTR("Drag-and-drop data");
} else {
return get_section_root_viewport()->gui.drag_description;
}
}
void Viewport::gui_set_drag_description(const String &p_description) {
gui.drag_description = p_description;
}
Variant Viewport::gui_get_drag_data() const {
ERR_READ_THREAD_GUARD_V(Variant());
return get_section_root_viewport()->gui.drag_data;
@ -4039,6 +4149,7 @@ void Viewport::_camera_2d_set(Camera2D *p_camera_2d) {
camera_2d = p_camera_2d;
}
#ifndef PHYSICS_2D_DISABLED
void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference) {
List<ObjectID> to_erase;
List<ObjectID> to_mouse_exit;
@ -4108,6 +4219,7 @@ void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paus
shapes_to_mouse_exit.pop_front();
}
}
#endif // PHYSICS_2D_DISABLED
AudioListener2D *Viewport::get_audio_listener_2d() const {
ERR_READ_THREAD_GUARD_V(nullptr);
@ -4235,6 +4347,7 @@ void Viewport::_audio_listener_3d_make_next_current(AudioListener3D *p_exclude)
}
}
#ifndef PHYSICS_3D_DISABLED
void Viewport::_collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
Transform3D object_transform = p_object->get_global_transform();
Transform3D camera_transform = p_camera->get_global_transform();
@ -4252,6 +4365,7 @@ void Viewport::_collision_object_3d_input_event(CollisionObject3D *p_object, Cam
physics_last_camera_transform = camera_transform;
physics_last_id = id;
}
#endif // PHYSICS_3D_DISABLED
Camera3D *Viewport::get_camera_3d() const {
ERR_READ_THREAD_GUARD_V(nullptr);
@ -4802,12 +4916,14 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture"), &Viewport::get_texture);
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
ClassDB::bind_method(D_METHOD("set_physics_object_picking", "enable"), &Viewport::set_physics_object_picking);
ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking);
ClassDB::bind_method(D_METHOD("set_physics_object_picking_sort", "enable"), &Viewport::set_physics_object_picking_sort);
ClassDB::bind_method(D_METHOD("get_physics_object_picking_sort"), &Viewport::get_physics_object_picking_sort);
ClassDB::bind_method(D_METHOD("set_physics_object_picking_first_only", "enable"), &Viewport::set_physics_object_picking_first_only);
ClassDB::bind_method(D_METHOD("get_physics_object_picking_first_only"), &Viewport::get_physics_object_picking_first_only);
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid);
ClassDB::bind_method(D_METHOD("push_text_input", "text"), &Viewport::push_text_input);
@ -4824,6 +4940,8 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("gui_cancel_drag"), &Viewport::gui_cancel_drag);
ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
ClassDB::bind_method(D_METHOD("gui_get_drag_description"), &Viewport::gui_get_drag_description);
ClassDB::bind_method(D_METHOD("gui_set_drag_description", "description"), &Viewport::gui_set_drag_description);
ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);
ClassDB::bind_method(D_METHOD("gui_is_drag_successful"), &Viewport::gui_is_drag_successful);
@ -4885,7 +5003,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mesh_lod_threshold", "pixels"), &Viewport::set_mesh_lod_threshold);
ClassDB::bind_method(D_METHOD("get_mesh_lod_threshold"), &Viewport::get_mesh_lod_threshold);
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking);
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
@ -4976,10 +5096,12 @@ void Viewport::_bind_methods() {
#ifndef _3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener_3d", "is_audio_listener_3d");
#endif // _3D_DISABLED
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
ADD_GROUP("Physics", "physics_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking"), "set_physics_object_picking", "get_physics_object_picking");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking_sort"), "set_physics_object_picking_sort", "get_physics_object_picking_sort");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking_first_only"), "set_physics_object_picking_first_only", "get_physics_object_picking_first_only");
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
ADD_GROUP("GUI", "gui_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled");
@ -5223,7 +5345,10 @@ void SubViewport::set_size_2d_override(const Size2i &p_size) {
Size2i SubViewport::get_size_2d_override() const {
ERR_READ_THREAD_GUARD_V(Size2i());
return _get_size_2d_override();
// Rounding will cause offset issues with the
// exact positioning of subwindows, but changing the
// type of size_2d_override would break compatibility.
return Size2i((_get_size_2d_override() + Size2(0.5, 0.5)).floor());
}
void SubViewport::set_size_2d_override_stretch(bool p_enable) {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef VIEWPORT_H
#define VIEWPORT_H
#pragma once
#include "scene/main/node.h"
#include "scene/resources/texture.h"
@ -252,7 +251,7 @@ private:
Transform2D stretch_transform;
Size2i size = Size2i(512, 512);
Size2i size_2d_override;
Size2 size_2d_override;
bool size_allocated = false;
RID contact_2d_debug;
@ -269,6 +268,7 @@ private:
bool snap_2d_transforms_to_pixel = false;
bool snap_2d_vertices_to_pixel = false;
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
bool physics_object_picking = false;
bool physics_object_picking_sort = false;
bool physics_object_picking_first_only = false;
@ -278,6 +278,7 @@ private:
Transform3D physics_last_object_transform;
Transform3D physics_last_camera_transform;
ObjectID physics_last_id;
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
bool handle_input_locally = true;
bool local_input_handled = false;
@ -366,7 +367,7 @@ private:
HashMap<int, ObjectID> touch_focus;
Control *mouse_focus = nullptr;
Control *mouse_click_grabber = nullptr;
BitField<MouseButtonMask> mouse_focus_mask;
BitField<MouseButtonMask> mouse_focus_mask = MouseButtonMask::NONE;
Control *key_focus = nullptr;
Control *mouse_over = nullptr;
LocalVector<Control *> mouse_over_hierarchy;
@ -384,6 +385,7 @@ private:
bool drag_attempted = false;
Variant drag_data; // Only used in root-Viewport and SubViewports, that are not children of a SubViewportContainer.
ObjectID drag_preview_id;
String drag_description;
Ref<SceneTreeTimer> tooltip_timer;
double tooltip_delay = 0.0;
bool roots_order_dirty = false;
@ -438,11 +440,14 @@ private:
String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_tooltip_owner = nullptr);
void _gui_cancel_tooltip();
void _gui_show_tooltip();
void _gui_show_tooltip_at(const Point2i &p_pos);
void _gui_remove_control(Control *p_control);
void _gui_hide_control(Control *p_control);
void _gui_update_mouse_over();
void _gui_force_drag_start();
void _gui_force_drag_cancel();
void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control);
void _gui_set_drag_preview(Control *p_base, Control *p_control);
Control *_gui_get_drag_preview();
@ -492,14 +497,16 @@ private:
void _window_start_resize(SubWindowResize p_edge, Window *p_window);
protected:
bool _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, bool p_allocated);
bool _set_size(const Size2i &p_size, const Size2 &p_size_2d_override, bool p_allocated);
Size2i _get_size() const;
Size2i _get_size_2d_override() const;
Size2 _get_size_2d_override() const;
bool _is_size_allocated() const;
void _notification(int p_what);
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
void _process_picking();
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
@ -509,6 +516,9 @@ public:
uint64_t get_processed_events_count() const { return event_count; }
void cancel_tooltip();
void show_tooltip(Control *p_control);
void update_canvas_items();
Rect2 get_visible_rect() const;
@ -609,14 +619,18 @@ public:
Point2 wrap_mouse_in_rect(const Vector2 &p_relative, const Rect2 &p_rect);
virtual void update_mouse_cursor_state();
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
void set_physics_object_picking_sort(bool p_enable);
bool get_physics_object_picking_sort();
void set_physics_object_picking_first_only(bool p_enable);
bool get_physics_object_picking_first_only();
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
Variant gui_get_drag_data() const;
String gui_get_drag_description() const;
void gui_set_drag_description(const String &p_description);
void gui_reset_canvas_sort_index();
int gui_get_canvas_sort_index();
@ -624,6 +638,7 @@ public:
void gui_release_focus();
Control *gui_get_focus_owner() const;
Control *gui_get_hovered_control() const;
Window *get_focused_subwindow() const { return gui.subwindow_focused; }
PackedStringArray get_configuration_warnings() const override;
@ -650,6 +665,7 @@ public:
bool gui_is_dragging() const;
bool gui_is_drag_successful() const;
void gui_cancel_drag();
void gui_perform_drop_at(const Point2 &p_pos, Control *p_control = nullptr);
Control *gui_find_control(const Point2 &p_global);
@ -719,12 +735,14 @@ private:
Camera2D *camera_2d = nullptr;
void _camera_2d_set(Camera2D *p_camera_2d);
#ifndef PHYSICS_2D_DISABLED
// Collider to frame
HashMap<ObjectID, uint64_t> physics_2d_mouseover;
// Collider & shape to frame
HashMap<Pair<ObjectID, int>, uint64_t, PairHash<ObjectID, int>> physics_2d_shape_mouseover;
// Cleans up colliders corresponding to old frames or all of them.
void _cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference = 0);
#endif // PHYSICS_2D_DISABLED
public:
AudioListener2D *get_audio_listener_2d() const;
@ -750,7 +768,9 @@ private:
void _audio_listener_3d_remove(AudioListener3D *p_listener);
void _audio_listener_3d_make_next_current(AudioListener3D *p_exclude);
#ifndef PHYSICS_3D_DISABLED
void _collision_object_3d_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
#endif // PHYSICS_3D_DISABLED
struct Camera3DOverrideData {
Transform3D transform;
@ -895,5 +915,3 @@ VARIANT_ENUM_CAST(Viewport::RenderInfo);
VARIANT_ENUM_CAST(Viewport::RenderInfoType);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureFilter);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureRepeat);
#endif // VIEWPORT_H

View file

@ -48,6 +48,8 @@ void Window::set_root_layout_direction(int p_root_dir) {
// Dynamic properties.
Window *Window::focused_window = nullptr;
bool Window::_set(const StringName &p_name, const Variant &p_value) {
ERR_MAIN_THREAD_GUARD_V(false);
String name = p_name;
@ -275,7 +277,7 @@ Window *Window::get_from_id(DisplayServer::WindowID p_window_id) {
if (p_window_id == DisplayServer::INVALID_WINDOW_ID) {
return nullptr;
}
return Object::cast_to<Window>(ObjectDB::get_instance(DisplayServer::get_singleton()->window_get_attached_instance_id(p_window_id)));
return ObjectDB::get_instance<Window>(DisplayServer::get_singleton()->window_get_attached_instance_id(p_window_id));
}
void Window::set_title(const String &p_title) {
@ -310,11 +312,11 @@ void Window::set_title(const String &p_title) {
#ifdef DEBUG_ENABLED
if (EngineDebugger::get_singleton() && window_id == DisplayServer::MAIN_WINDOW_ID && !Engine::get_singleton()->is_project_manager_hint()) {
Array arr;
arr.push_back(tr_title);
Array arr = { tr_title };
EngineDebugger::get_singleton()->send_message("window:title", arr);
}
#endif
queue_accessibility_update();
}
String Window::get_title() const {
@ -688,6 +690,11 @@ void Window::_make_window() {
}
}
if (get_tree() && get_tree()->is_accessibility_supported()) {
get_tree()->_accessibility_force_update();
_accessibility_notify_enter(this);
}
_update_window_callbacks();
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
@ -719,6 +726,10 @@ void Window::_clear_window() {
_update_from_window();
if (get_tree() && get_tree()->is_accessibility_supported()) {
_accessibility_notify_exit(this);
}
DisplayServer::get_singleton()->delete_sub_window(window_id);
window_id = DisplayServer::INVALID_WINDOW_ID;
@ -750,6 +761,14 @@ void Window::_rect_changed_callback(const Rect2i &p_callback) {
size = p_callback.size;
_update_viewport_size();
}
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
Vector2 sz_out = DisplayServer::get_singleton()->window_get_size_with_decorations(window_id);
Vector2 pos_out = DisplayServer::get_singleton()->window_get_position_with_decorations(window_id);
Vector2 sz_in = DisplayServer::get_singleton()->window_get_size(window_id);
Vector2 pos_in = DisplayServer::get_singleton()->window_get_position(window_id);
DisplayServer::get_singleton()->accessibility_set_window_rect(window_id, Rect2(pos_out, sz_out), Rect2(pos_in, sz_in));
}
queue_accessibility_update();
}
void Window::_propagate_window_notification(Node *p_node, int p_notification) {
@ -808,12 +827,15 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
} break;
case DisplayServer::WINDOW_EVENT_FOCUS_IN: {
focused = true;
focused_window = this;
_propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_IN);
emit_signal(SceneStringName(focus_entered));
} break;
case DisplayServer::WINDOW_EVENT_FOCUS_OUT: {
focused = false;
if (focused_window == this) {
focused_window = nullptr;
}
_propagate_window_notification(this, NOTIFICATION_WM_WINDOW_FOCUS_OUT);
emit_signal(SceneStringName(focus_exited));
} break;
@ -836,6 +858,9 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
case DisplayServer::WINDOW_EVENT_TITLEBAR_CHANGE: {
emit_signal(SNAME("titlebar_changed"));
} break;
case DisplayServer::WINDOW_EVENT_FORCE_CLOSE: {
hide();
} break;
}
}
@ -866,6 +891,36 @@ void Window::hide() {
set_visible(false);
}
void Window::_accessibility_notify_enter(Node *p_node) {
p_node->queue_accessibility_update();
if (p_node != this) {
const Window *window = Object::cast_to<Window>(p_node);
if (window && !window->is_embedded()) {
return;
}
}
for (int i = 0; i < p_node->get_child_count(); i++) {
_accessibility_notify_enter(p_node->get_child(i));
}
}
void Window::_accessibility_notify_exit(Node *p_node) {
p_node->notification(Node::NOTIFICATION_ACCESSIBILITY_INVALIDATE);
if (p_node != this) {
const Window *window = Object::cast_to<Window>(p_node);
if (window && !window->is_embedded()) {
return;
}
}
for (int i = 0; i < p_node->get_child_count(); i++) {
_accessibility_notify_exit(p_node->get_child(i));
}
}
void Window::set_visible(bool p_visible) {
ERR_MAIN_THREAD_GUARD;
if (visible == p_visible) {
@ -905,9 +960,11 @@ void Window::set_visible(bool p_visible) {
}
}
embedder->_sub_window_register(this);
embedder->queue_accessibility_update();
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
} else {
embedder->_sub_window_remove(this);
embedder->queue_accessibility_update();
embedder = nullptr;
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
}
@ -916,7 +973,11 @@ void Window::set_visible(bool p_visible) {
if (!visible) {
focused = false;
if (focused_window == this) {
focused_window = nullptr;
}
}
notification(NOTIFICATION_VISIBILITY_CHANGED);
emit_signal(SceneStringName(visibility_changed));
@ -1133,7 +1194,7 @@ void Window::_update_viewport_size() {
//update the viewport part
Size2i final_size;
Size2i final_size_override;
Size2 final_size_override;
Rect2i attach_to_screen_rect(Point2i(), size);
double font_oversampling = 1.0;
window_transform = Transform2D();
@ -1330,9 +1391,78 @@ Viewport *Window::get_embedder() const {
return nullptr;
}
RID Window::get_accessibility_element() const {
if (is_part_of_edited_scene()) {
return RID();
}
if (get_embedder()) {
return Node::get_accessibility_element();
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
return DisplayServer::get_singleton()->accessibility_get_window_root(window_id);
} else {
return RID();
}
}
RID Window::get_focused_accessibility_element() const {
if (window_id == DisplayServer::MAIN_WINDOW_ID) {
if (get_child_count() > 0) {
return get_child(0)->get_focused_accessibility_element(); // Try scene tree root node.
}
}
return Node::get_focused_accessibility_element();
}
void Window::_notification(int p_what) {
ERR_MAIN_THREAD_GUARD;
switch (p_what) {
case NOTIFICATION_ACCESSIBILITY_INVALIDATE: {
accessibility_title_element = RID();
accessibility_announcement_element = RID();
} break;
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
RID ae = get_accessibility_element();
ERR_FAIL_COND(ae.is_null());
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_WINDOW);
DisplayServer::get_singleton()->accessibility_update_set_name(ae, tr_title);
DisplayServer::get_singleton()->accessibility_update_set_flag(ae, DisplayServer::AccessibilityFlags::FLAG_MODAL, exclusive);
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_FOCUS, callable_mp(this, &Window::_accessibility_action_grab_focus));
DisplayServer::get_singleton()->accessibility_update_set_flag(ae, DisplayServer::AccessibilityFlags::FLAG_HIDDEN, !visible);
if (get_embedder()) {
Control *parent_ctrl = Object::cast_to<Control>(get_parent());
Transform2D parent_tr = parent_ctrl ? parent_ctrl->get_global_transform() : Transform2D();
Transform2D tr;
tr.set_origin(position);
DisplayServer::get_singleton()->accessibility_update_set_transform(ae, parent_tr.affine_inverse() * tr);
DisplayServer::get_singleton()->accessibility_update_set_bounds(ae, Rect2(Point2(), size));
if (accessibility_title_element.is_null()) {
accessibility_title_element = DisplayServer::get_singleton()->accessibility_create_sub_element(ae, DisplayServer::AccessibilityRole::ROLE_TITLE_BAR);
}
int w = get_theme_constant(SNAME("title_height"));
DisplayServer::get_singleton()->accessibility_update_set_name(accessibility_title_element, tr_title);
DisplayServer::get_singleton()->accessibility_update_set_bounds(accessibility_title_element, Rect2(Vector2(0, -w), Size2(size.x, w)));
} else {
DisplayServer::get_singleton()->accessibility_update_set_transform(ae, Transform2D());
DisplayServer::get_singleton()->accessibility_update_set_bounds(ae, Rect2(Point2(), size));
if (accessibility_announcement_element.is_null()) {
accessibility_announcement_element = DisplayServer::get_singleton()->accessibility_create_sub_element(ae, DisplayServer::AccessibilityRole::ROLE_STATIC_TEXT);
}
if (announcement.is_empty()) {
DisplayServer::get_singleton()->accessibility_update_set_live(accessibility_announcement_element, DisplayServer::LIVE_OFF);
} else {
DisplayServer::get_singleton()->accessibility_update_set_name(accessibility_announcement_element, announcement);
DisplayServer::get_singleton()->accessibility_update_set_live(accessibility_announcement_element, DisplayServer::LIVE_ASSERTIVE);
}
}
} break;
case NOTIFICATION_POSTINITIALIZE: {
initialized = true;
@ -1387,6 +1517,7 @@ void Window::_notification(int p_what) {
// It's the root window!
visible = true; // Always visible.
window_id = DisplayServer::MAIN_WINDOW_ID;
focused_window = this;
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
_update_from_window();
// Since this window already exists (created on start), we must update pos and size from it.
@ -1465,6 +1596,7 @@ void Window::_notification(int p_what) {
}
}
}
queue_accessibility_update();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@ -1483,6 +1615,9 @@ void Window::_notification(int p_what) {
set_theme_context(nullptr, false);
accessibility_title_element = RID();
accessibility_announcement_element = RID();
if (transient) {
_clear_transient();
}
@ -1602,7 +1737,12 @@ bool Window::is_using_font_oversampling() const {
DisplayServer::WindowID Window::get_window_id() const {
ERR_READ_THREAD_GUARD_V(DisplayServer::INVALID_WINDOW_ID);
if (embedder) {
if (get_embedder()) {
#ifdef TOOLS_ENABLED
if (is_part_of_edited_scene()) {
return DisplayServer::MAIN_WINDOW_ID;
}
#endif
return parent->get_window_id();
}
return window_id;
@ -1860,12 +2000,19 @@ void Window::popup(const Rect2i &p_screen_rect) {
// Update window size to calculate the actual window size based on contents minimum size and minimum size.
_update_window_size();
bool should_fit = !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SELF_FITTING_WINDOWS);
if (p_screen_rect != Rect2i()) {
set_position(p_screen_rect.position);
int screen_id = DisplayServer::get_singleton()->get_screen_from_rect(p_screen_rect);
Size2i screen_size = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id).size;
Size2i new_size = p_screen_rect.size.min(screen_size);
set_size(new_size);
if (should_fit) {
int screen_id = DisplayServer::get_singleton()->get_screen_from_rect(p_screen_rect);
Size2i screen_size = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id).size;
Size2i new_size = p_screen_rect.size.min(screen_size);
set_size(new_size);
} else {
set_size(p_screen_rect.size);
}
}
Rect2i adjust = _popup_adjust_rect();
@ -1893,7 +2040,7 @@ void Window::popup(const Rect2i &p_screen_rect) {
int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id());
parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id);
}
if (parent_rect != Rect2i() && !parent_rect.intersects(Rect2i(position, size))) {
if (should_fit && parent_rect != Rect2i() && !parent_rect.intersects(Rect2i(position, size))) {
ERR_PRINT(vformat("Window %d spawned at invalid position: %s.", get_window_id(), position));
set_position((parent_rect.size - size) / 2);
}
@ -2071,6 +2218,11 @@ Rect2i Window::get_usable_parent_rect() const {
return parent_rect;
}
void Window::accessibility_announcement(const String &p_announcement) {
announcement = p_announcement;
queue_accessibility_update();
}
void Window::add_child_notify(Node *p_child) {
if (is_inside_tree() && wrap_controls) {
child_controls_changed();
@ -2372,6 +2524,18 @@ Variant Window::get_theme_item(Theme::DataType p_data_type, const StringName &p_
Ref<Texture2D> Window::get_editor_theme_icon(const StringName &p_name) const {
return get_theme_icon(p_name, SNAME("EditorIcons"));
}
Ref<Texture2D> Window::get_editor_theme_native_menu_icon(const StringName &p_name, bool p_global_menu, bool p_dark_mode) const {
if (!p_global_menu) {
return get_theme_icon(p_name, SNAME("EditorIcons"));
}
if (p_dark_mode && has_theme_icon(String(p_name) + "Dark", SNAME("EditorIcons"))) {
return get_theme_icon(String(p_name) + "Dark", SNAME("EditorIcons"));
} else if (!p_dark_mode && has_theme_icon(String(p_name) + "Light", SNAME("EditorIcons"))) {
return get_theme_icon(String(p_name) + "Light", SNAME("EditorIcons"));
}
return get_theme_icon(p_name, SNAME("EditorIcons"));
}
#endif
bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
@ -2885,8 +3049,6 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);
ClassDB::bind_method(D_METHOD("get_window_id"), &Window::get_window_id);
ClassDB::bind_method(D_METHOD("set_initial_position", "initial_position"), &Window::set_initial_position);
ClassDB::bind_method(D_METHOD("get_initial_position"), &Window::get_initial_position);
@ -3034,6 +3196,10 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Window::get_theme_default_font);
ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Window::get_theme_default_font_size);
ClassDB::bind_method(D_METHOD("get_window_id"), &Window::get_window_id);
ClassDB::bind_static_method("Window", D_METHOD("get_focused_window"), &Window::get_focused_window);
ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction);
ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction);
ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl);
@ -3084,6 +3250,9 @@ void Window::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "sharp_corners"), "set_flag", "get_flag", FLAG_SHARP_CORNERS);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "exclude_from_capture"), "set_flag", "get_flag", FLAG_EXCLUDE_FROM_CAPTURE);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_wm_hint"), "set_flag", "get_flag", FLAG_POPUP_WM_HINT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "minimize_disabled"), "set_flag", "get_flag", FLAG_MINIMIZE_DISABLED);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "maximize_disabled"), "set_flag", "get_flag", FLAG_MAXIMIZE_DISABLED);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_native"), "set_force_native", "get_force_native");
ADD_GROUP("Limits", "");
@ -3140,6 +3309,9 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH);
BIND_ENUM_CONSTANT(FLAG_SHARP_CORNERS);
BIND_ENUM_CONSTANT(FLAG_EXCLUDE_FROM_CAPTURE);
BIND_ENUM_CONSTANT(FLAG_POPUP_WM_HINT);
BIND_ENUM_CONSTANT(FLAG_MINIMIZE_DISABLED);
BIND_ENUM_CONSTANT(FLAG_MAXIMIZE_DISABLED);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
@ -3204,6 +3376,9 @@ Window::Window() {
}
Window::~Window() {
if (focused_window == this) {
focused_window = nullptr;
}
memdelete(theme_owner);
// Resources need to be disconnected.

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef WINDOW_H
#define WINDOW_H
#pragma once
#include "scene/main/viewport.h"
#include "scene/resources/theme.h"
@ -65,6 +64,9 @@ public:
FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH,
FLAG_SHARP_CORNERS = DisplayServer::WINDOW_FLAG_SHARP_CORNERS,
FLAG_EXCLUDE_FROM_CAPTURE = DisplayServer::WINDOW_FLAG_EXCLUDE_FROM_CAPTURE,
FLAG_POPUP_WM_HINT = DisplayServer::WINDOW_FLAG_POPUP_WM_HINT,
FLAG_MINIMIZE_DISABLED = DisplayServer::WINDOW_FLAG_MINIMIZE_DISABLED,
FLAG_MAXIMIZE_DISABLED = DisplayServer::WINDOW_FLAG_MAXIMIZE_DISABLED,
FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
};
@ -103,7 +105,7 @@ public:
DEFAULT_WINDOW_SIZE = 100,
};
// Keep synced with enum hint for `initial_position` property.
// Keep synced with enum hint for `initial_position` property and `display/window/size/initial_position_type` project setting.
enum WindowInitialPosition {
WINDOW_INITIAL_POSITION_ABSOLUTE,
WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN,
@ -154,9 +156,15 @@ private:
ContentScaleStretch content_scale_stretch = CONTENT_SCALE_STRETCH_FRACTIONAL;
real_t content_scale_factor = 1.0;
RID accessibility_title_element;
RID accessibility_announcement_element;
String announcement;
void _make_window();
void _clear_window();
void _update_from_window();
void _accessibility_notify_enter(Node *p_node);
void _accessibility_notify_exit(Node *p_node);
bool _try_parent_dialog(Node *p_from_node);
@ -180,6 +188,8 @@ private:
void _make_transient();
void _set_transient_exclusive_child(bool p_clear_invalid = false);
static Window *focused_window;
ThemeOwner *theme_owner = nullptr;
Ref<Theme> theme;
StringName theme_type_variation;
@ -260,6 +270,10 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
void _validate_property(PropertyInfo &p_property) const;
void _accessibility_action_grab_focus(const Variant &p_data) {
grab_focus();
}
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
@ -275,6 +289,9 @@ public:
static void set_root_layout_direction(int p_root_dir);
static Window *get_from_id(DisplayServer::WindowID p_window_id);
RID get_accessibility_element() const override;
virtual RID get_focused_accessibility_element() const override;
void set_title(const String &p_title);
String get_title() const;
String get_translated_title() const;
@ -379,6 +396,7 @@ public:
void child_controls_changed();
Window *get_exclusive_child() const { return exclusive_child; }
HashSet<Window *> get_transient_children() const { return transient_children; }
Window *get_parent_visible_window() const;
Viewport *get_parent_viewport() const;
@ -406,6 +424,8 @@ public:
Rect2i get_usable_parent_rect() const;
void accessibility_announcement(const String &p_announcement);
// Internationalization.
void set_layout_direction(LayoutDirection p_direction);
@ -457,6 +477,7 @@ public:
Variant get_theme_item(Theme::DataType p_data_type, const StringName &p_name, const StringName &p_theme_type = StringName()) const;
#ifdef TOOLS_ENABLED
Ref<Texture2D> get_editor_theme_icon(const StringName &p_name) const;
Ref<Texture2D> get_editor_theme_native_menu_icon(const StringName &p_name, bool p_global_menu, bool p_dark_mode) const;
#endif
bool has_theme_icon_override(const StringName &p_name) const;
@ -477,8 +498,6 @@ public:
Ref<Font> get_theme_default_font() const;
int get_theme_default_font_size() const;
//
virtual Transform2D get_final_transform() const override;
virtual Transform2D get_screen_transform_internal(bool p_absolute_position = false) const override;
virtual Transform2D get_popup_base_transform() const override;
@ -487,6 +506,7 @@ public:
Rect2i get_parent_rect() const;
virtual DisplayServer::WindowID get_window_id() const override;
static Window *get_focused_window() { return focused_window; }
virtual Size2 _get_contents_minimum_size() const;
@ -501,5 +521,3 @@ VARIANT_ENUM_CAST(Window::ContentScaleAspect);
VARIANT_ENUM_CAST(Window::ContentScaleStretch);
VARIANT_ENUM_CAST(Window::LayoutDirection);
VARIANT_ENUM_CAST(Window::WindowInitialPosition);
#endif // WINDOW_H