Fix changing `gui_embed_subwindows` while a child window is displayed

Changing `gui_embed_subwindows` while a child window is displayed can lead
to crashes or other unintended behavior.
This PR adds checks to prevent the change while child windows are
displayed.
This commit is contained in:
Markus Sauermann 2023-12-16 01:33:12 +01:00
parent f8a2a91936
commit 62587d2d19
1 changed files with 60 additions and 1 deletions

View File

@ -3848,7 +3848,66 @@ Viewport *Viewport::get_parent_viewport() const {
void Viewport::set_embedding_subwindows(bool p_embed) {
ERR_THREAD_GUARD;
gui.embed_subwindows_hint = p_embed;
if (gui.embed_subwindows_hint == p_embed) {
return;
}
bool allow_change = true;
if (!is_inside_tree()) {
// Change can happen since no child window is displayed.
} else if (gui.embed_subwindows_hint) {
if (!gui.sub_windows.is_empty()) {
// Prevent change when this viewport has embedded windows.
allow_change = false;
}
} else {
Viewport *vp = this;
while (true) {
if (!vp->get_parent()) {
// Root window reached.
break;
}
vp = vp->get_parent()->get_viewport();
if (vp->is_embedding_subwindows()) {
for (int i = 0; i < vp->gui.sub_windows.size(); i++) {
if (is_ancestor_of(vp->gui.sub_windows[i].window)) {
// Prevent change when this viewport has child windows that are displayed in an ancestor viewport.
allow_change = false;
break;
}
}
}
}
if (allow_change) {
Vector<int> wl = DisplayServer::get_singleton()->get_window_list();
for (int index = 0; index < wl.size(); index++) {
DisplayServer::WindowID wid = wl[index];
if (wid == DisplayServer::INVALID_WINDOW_ID) {
continue;
}
ObjectID woid = DisplayServer::get_singleton()->window_get_attached_instance_id(wid);
if (woid.is_null()) {
continue;
}
Window *w = Object::cast_to<Window>(ObjectDB::get_instance(woid));
if (w && is_ancestor_of(w)) {
// Prevent change when this viewport has child windows that are displayed as native windows.
allow_change = false;
break;
}
}
}
}
if (allow_change) {
gui.embed_subwindows_hint = p_embed;
} else {
WARN_PRINT("Can't change \"gui_embed_subwindows\" while a child window is displayed. Consider hiding all child windows before changing this value.");
}
}
bool Viewport::is_embedding_subwindows() const {