summaryrefslogtreecommitdiffstats
path: root/scene/main
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main')
-rw-r--r--scene/main/canvas_item.cpp18
-rw-r--r--scene/main/node.cpp107
-rw-r--r--scene/main/resource_preloader.cpp5
-rw-r--r--scene/main/scene_tree.cpp19
-rw-r--r--scene/main/scene_tree.h1
-rw-r--r--scene/main/viewport.cpp37
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/main/window.cpp32
8 files changed, 159 insertions, 62 deletions
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index d2735b968b..4ee81e5cb0 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -891,18 +891,22 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
* notification anyway).
*/
- if (p_node->block_transform_notify || p_node->_is_global_invalid()) {
+ if (/*p_node->xform_change.in_list() &&*/ p_node->_is_global_invalid()) {
return; //nothing to do
}
p_node->_set_global_invalid(true);
- if (p_node->notify_transform && !p_node->xform_change.in_list() && p_node->is_inside_tree()) {
- if (is_accessible_from_caller_thread()) {
- get_tree()->xform_change_list.add(&p_node->xform_change);
- } else {
- // Should be rare, but still needs to be handled.
- MessageQueue::get_singleton()->push_callable(callable_mp(p_node, &CanvasItem::_notify_transform_deferred));
+ if (p_node->notify_transform && !p_node->xform_change.in_list()) {
+ if (!p_node->block_transform_notify) {
+ if (p_node->is_inside_tree()) {
+ if (is_accessible_from_caller_thread()) {
+ get_tree()->xform_change_list.add(&p_node->xform_change);
+ } else {
+ // Should be rare, but still needs to be handled.
+ MessageQueue::get_singleton()->push_callable(callable_mp(p_node, &CanvasItem::_notify_transform_deferred));
+ }
+ }
}
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index e730f47607..820cb7571f 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -202,6 +202,11 @@ void Node::_notification(int p_notification) {
_clean_up_owner();
}
+ while (!data.owned.is_empty()) {
+ Node *n = data.owned.back()->get();
+ n->_clean_up_owner(); // This will change data.owned. So it's impossible to loop over the list in the usual manner.
+ }
+
if (data.parent) {
data.parent->remove_child(this);
}
@@ -1415,6 +1420,14 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead.");
_validate_child_name(p_child, p_force_readable_name);
+
+#ifdef DEBUG_ENABLED
+ if (p_child->data.owner && !p_child->data.owner->is_ancestor_of(p_child)) {
+ // Owner of p_child should be ancestor of p_child.
+ WARN_PRINT(vformat("Adding '%s' as child to '%s' will make owner '%s' inconsistent. Consider unsetting the owner beforehand.", p_child->get_name(), get_name(), p_child->data.owner->get_name()));
+ }
+#endif // DEBUG_ENABLED
+
_add_child_nocheck(p_child, p_child->data.name, p_internal);
}
@@ -2515,44 +2528,6 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
}
}
- for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
- Node *current_node = node->get_node(get_path_to(N->get()));
- ERR_CONTINUE(!current_node);
-
- if (p_flags & DUPLICATE_SCRIPTS) {
- bool is_valid = false;
- Variant scr = N->get()->get(script_property_name, &is_valid);
- if (is_valid) {
- current_node->set(script_property_name, scr);
- }
- }
-
- List<PropertyInfo> plist;
- N->get()->get_property_list(&plist);
-
- for (const PropertyInfo &E : plist) {
- if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
- continue;
- }
- String name = E.name;
- if (name == script_property_name) {
- continue;
- }
-
- Variant value = N->get()->get(name).duplicate(true);
-
- if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) {
- Resource *res = Object::cast_to<Resource>(value);
- if (res) { // Duplicate only if it's a resource
- current_node->set(name, res->duplicate());
- }
-
- } else {
- current_node->set(name, value);
- }
- }
- }
-
if (get_name() != String()) {
node->set_name(get_name());
}
@@ -2618,6 +2593,62 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
}
}
+ for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
+ Node *current_node = node->get_node(get_path_to(N->get()));
+ ERR_CONTINUE(!current_node);
+
+ if (p_flags & DUPLICATE_SCRIPTS) {
+ bool is_valid = false;
+ Variant scr = N->get()->get(script_property_name, &is_valid);
+ if (is_valid) {
+ current_node->set(script_property_name, scr);
+ }
+ }
+
+ List<PropertyInfo> plist;
+ N->get()->get_property_list(&plist);
+
+ for (const PropertyInfo &E : plist) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
+ String name = E.name;
+ if (name == script_property_name) {
+ continue;
+ }
+
+ Variant value = N->get()->get(name).duplicate(true);
+
+ if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) {
+ Resource *res = Object::cast_to<Resource>(value);
+ if (res) { // Duplicate only if it's a resource
+ current_node->set(name, res->duplicate());
+ }
+
+ } else {
+ // If property points to a node which is owned by a node we are duplicating, update its path.
+ if (value.get_type() == Variant::OBJECT) {
+ Node *property_node = Object::cast_to<Node>(value);
+ if (property_node && is_ancestor_of(property_node)) {
+ value = current_node->get_node_or_null(get_path_to(property_node));
+ }
+ } else if (value.get_type() == Variant::ARRAY) {
+ Array arr = value;
+ if (arr.get_typed_builtin() == Variant::OBJECT) {
+ for (int i = 0; i < arr.size(); i++) {
+ Node *property_node = Object::cast_to<Node>(arr[i]);
+ if (property_node && is_ancestor_of(property_node)) {
+ arr[i] = current_node->get_node_or_null(get_path_to(property_node));
+ }
+ }
+ value = arr;
+ }
+ }
+ current_node->set(name, value);
+ }
+ }
+ }
+
return node;
}
diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp
index de42b63548..fe0e82370a 100644
--- a/scene/main/resource_preloader.cpp
+++ b/scene/main/resource_preloader.cpp
@@ -40,12 +40,11 @@ void ResourcePreloader::_set_resources(const Array &p_data) {
ERR_FAIL_COND(names.size() != resdata.size());
for (int i = 0; i < resdata.size(); i++) {
- String name = names[i];
Ref<Resource> resource = resdata[i];
ERR_CONTINUE(!resource.is_valid());
- resources[name] = resource;
+ resources[names[i]] = resource;
- //add_resource(name,resource);
+ //add_resource(names[i],resource);
}
}
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index d3347bc304..4417007b9d 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -515,6 +515,10 @@ bool SceneTree::process(double p_time) {
_flush_delete_queue();
+ if (unlikely(pending_new_scene)) {
+ _flush_scene_change();
+ }
+
process_timers(p_time, false); //go through timers
process_tweens(p_time, false);
@@ -550,10 +554,6 @@ bool SceneTree::process(double p_time) {
#endif // _3D_DISABLED
#endif // TOOLS_ENABLED
- if (unlikely(pending_new_scene)) {
- _flush_scene_change();
- }
-
return _quit;
}
@@ -1302,6 +1302,16 @@ bool SceneTree::has_group(const StringName &p_identifier) const {
return group_map.has(p_identifier);
}
+int SceneTree::get_node_count_in_group(const StringName &p_group) const {
+ _THREAD_SAFE_METHOD_
+ HashMap<StringName, Group>::ConstIterator E = group_map.find(p_group);
+ if (!E) {
+ return 0;
+ }
+
+ return E->value.nodes.size();
+}
+
Node *SceneTree::get_first_node_in_group(const StringName &p_group) {
_THREAD_SAFE_METHOD_
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
@@ -1617,6 +1627,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group);
ClassDB::bind_method(D_METHOD("get_first_node_in_group", "group"), &SceneTree::get_first_node_in_group);
+ ClassDB::bind_method(D_METHOD("get_node_count_in_group", "group"), &SceneTree::get_node_count_in_group);
ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene);
ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene);
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index e1597d3890..618ac275ff 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -385,6 +385,7 @@ public:
void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list);
Node *get_first_node_in_group(const StringName &p_group);
bool has_group(const StringName &p_identifier) const;
+ int get_node_count_in_group(const StringName &p_group) const;
//void change_scene(const String& p_path);
//Node *get_loaded_scene();
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 43bdb1395b..89ec5636ab 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2451,6 +2451,14 @@ void Viewport::_gui_update_mouse_over() {
return;
}
+ if (gui.sending_mouse_enter_exit_notifications) {
+ // If notifications are already being sent, delay call to next frame.
+ if (get_tree() && !get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over))) {
+ get_tree()->connect(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over), CONNECT_ONE_SHOT);
+ }
+ return;
+ }
+
// Rebuild the mouse over hierarchy.
LocalVector<Control *> new_mouse_over_hierarchy;
LocalVector<Control *> needs_enter;
@@ -2507,6 +2515,8 @@ void Viewport::_gui_update_mouse_over() {
return;
}
+ gui.sending_mouse_enter_exit_notifications = true;
+
// Send Mouse Exit Self notification.
if (gui.mouse_over && !needs_exit.is_empty() && needs_exit[0] == (int)gui.mouse_over_hierarchy.size() - 1) {
gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF);
@@ -2528,6 +2538,8 @@ void Viewport::_gui_update_mouse_over() {
for (int i = needs_enter.size() - 1; i >= 0; i--) {
needs_enter[i]->notification(Control::NOTIFICATION_MOUSE_ENTER);
}
+
+ gui.sending_mouse_enter_exit_notifications = false;
}
Window *Viewport::get_base_window() const {
@@ -3200,14 +3212,20 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
gui.mouse_over = over;
gui.mouse_over_hierarchy.reserve(gui.mouse_over_hierarchy.size() + over_ancestors.size());
+ gui.sending_mouse_enter_exit_notifications = true;
+
// Send Mouse Enter notifications to parents first.
for (int i = over_ancestors.size() - 1; i >= 0; i--) {
- over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER);
gui.mouse_over_hierarchy.push_back(over_ancestors[i]);
+ over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER);
}
// Send Mouse Enter Self notification.
- gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF);
+ if (gui.mouse_over) {
+ gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF);
+ }
+
+ gui.sending_mouse_enter_exit_notifications = false;
notify_embedded_viewports = true;
}
@@ -3250,6 +3268,12 @@ void Viewport::_mouse_leave_viewport() {
}
void Viewport::_drop_mouse_over(Control *p_until_control) {
+ if (gui.sending_mouse_enter_exit_notifications) {
+ // If notifications are already being sent, defer call.
+ callable_mp(this, &Viewport::_drop_mouse_over).call_deferred(p_until_control);
+ return;
+ }
+
_gui_cancel_tooltip();
SubViewportContainer *c = Object::cast_to<SubViewportContainer>(gui.mouse_over);
if (c) {
@@ -3261,6 +3285,8 @@ void Viewport::_drop_mouse_over(Control *p_until_control) {
v->_mouse_leave_viewport();
}
}
+
+ gui.sending_mouse_enter_exit_notifications = true;
if (gui.mouse_over && gui.mouse_over->is_inside_tree()) {
gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF);
}
@@ -3274,6 +3300,7 @@ void Viewport::_drop_mouse_over(Control *p_until_control) {
}
}
gui.mouse_over_hierarchy.resize(notification_until);
+ gui.sending_mouse_enter_exit_notifications = false;
}
void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
@@ -3491,6 +3518,11 @@ Control *Viewport::gui_get_focus_owner() const {
return gui.key_focus;
}
+Control *Viewport::gui_get_hovered_control() const {
+ ERR_READ_THREAD_GUARD_V(nullptr);
+ return gui.mouse_over;
+}
+
void Viewport::set_msaa_2d(MSAA p_msaa) {
ERR_MAIN_THREAD_GUARD;
ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
@@ -4530,6 +4562,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("gui_release_focus"), &Viewport::gui_release_focus);
ClassDB::bind_method(D_METHOD("gui_get_focus_owner"), &Viewport::gui_get_focus_owner);
+ ClassDB::bind_method(D_METHOD("gui_get_hovered_control"), &Viewport::gui_get_hovered_control);
ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input);
ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 82a9bfc438..43a89c8a0b 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -362,6 +362,7 @@ private:
Control *key_focus = nullptr;
Control *mouse_over = nullptr;
LocalVector<Control *> mouse_over_hierarchy;
+ bool sending_mouse_enter_exit_notifications = false;
Window *subwindow_over = nullptr; // mouse_over and subwindow_over are mutually exclusive. At all times at least one of them is nullptr.
Window *windowmanager_window_over = nullptr; // Only used in root Viewport.
Control *drag_mouse_over = nullptr;
@@ -609,6 +610,7 @@ public:
void gui_release_focus();
Control *gui_get_focus_owner() const;
+ Control *gui_get_hovered_control() const;
PackedStringArray get_configuration_warnings() const override;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 0d554de6f4..98b207bd3c 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -284,7 +284,13 @@ void Window::set_title(const String &p_title) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
- _update_window_size();
+ if (keep_title_visible) {
+ Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
+ Size2i size_limit = get_clamped_minimum_size();
+ if (title_size.x > size_limit.x || title_size.y > size_limit.y) {
+ _update_window_size();
+ }
+ }
}
}
@@ -681,6 +687,9 @@ void Window::_propagate_window_notification(Node *p_node, int p_notification) {
void Window::_event_callback(DisplayServer::WindowEvent p_event) {
switch (p_event) {
case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: {
+ if (!is_inside_tree()) {
+ return;
+ }
Window *root = get_tree()->get_root();
if (root->gui.windowmanager_window_over) {
#ifdef DEV_ENABLED
@@ -696,6 +705,9 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
}
} break;
case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: {
+ if (!is_inside_tree()) {
+ return;
+ }
Window *root = get_tree()->get_root();
if (!root->gui.windowmanager_window_over) {
#ifdef DEV_ENABLED
@@ -955,6 +967,10 @@ Size2i Window::_clamp_window_size(const Size2i &p_size) {
void Window::_update_window_size() {
Size2i size_limit = get_clamped_minimum_size();
+ if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID && keep_title_visible) {
+ Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
+ size_limit = size_limit.max(title_size);
+ }
size = size.max(size_limit);
@@ -986,12 +1002,6 @@ void Window::_update_window_size() {
}
DisplayServer::get_singleton()->window_set_max_size(max_size_used, window_id);
-
- if (keep_title_visible) {
- Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
- size_limit = size_limit.max(title_size);
- }
-
DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id);
DisplayServer::get_singleton()->window_set_size(size, window_id);
}
@@ -1291,7 +1301,13 @@ void Window::_notification(int p_what) {
if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
- _update_window_size();
+ if (keep_title_visible) {
+ Size2i title_size = DisplayServer::get_singleton()->window_get_title_size(tr_title, window_id);
+ Size2i size_limit = get_clamped_minimum_size();
+ if (title_size.x > size_limit.x || title_size.y > size_limit.y) {
+ _update_window_size();
+ }
+ }
}
} break;