2
0
Эх сурвалжийг харах

Open sub-windows as embedded if the OS does not support them

Juan Linietsky 5 жил өмнө
parent
commit
c7b4dcae2f

+ 4 - 1
editor/animation_track_editor.cpp

@@ -2853,7 +2853,10 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
 		Vector2 theme_ofs = path->get_theme_stylebox("normal", "LineEdit")->get_offset();
 		path->set_position(get_global_position() + path_rect.position - theme_ofs);
 		path->set_size(path_rect.size);
-		path->show_modal();
+#ifndef _MSC_VER
+#warning show modal not supported any longer, need to move this to a popup
+#endif
+		path->show();
 		path->grab_focus();
 		path->set_cursor_position(path->get_text().length());
 		clicking_on_name = false;

+ 1 - 4
editor/editor_node.cpp

@@ -264,11 +264,8 @@ void EditorNode::_update_title() {
 
 void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
 
-	if (Node::get_viewport()->get_modal_stack_top())
-		return; //ignore because of modal window
-
 	Ref<InputEventKey> k = p_event;
-	if (k.is_valid() && k->is_pressed() && !k->is_echo() && !gui_base->get_viewport()->gui_has_modal_stack()) {
+	if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
 
 		EditorPlugin *old_editor = editor_plugin_screen;
 

+ 10 - 9
editor/editor_themes.cpp

@@ -911,15 +911,16 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	style_window->set_border_width(MARGIN_TOP, 24 * EDSCALE);
 	style_window->set_expand_margin_size(MARGIN_TOP, 24 * EDSCALE);
 
-	theme->set_stylebox("panel", "AcceptDialog", style_default);
-	theme->set_stylebox("panel_window", "AcceptDialog", style_window);
-	theme->set_color("title_color", "AcceptDialog", font_color);
-	theme->set_icon("close", "AcceptDialog", theme->get_icon("GuiClose", "EditorIcons"));
-	theme->set_icon("close_highlight", "AcceptDialog", theme->get_icon("GuiClose", "EditorIcons"));
-	theme->set_constant("close_h_ofs", "AcceptDialog", 22 * EDSCALE);
-	theme->set_constant("close_v_ofs", "AcceptDialog", 20 * EDSCALE);
-	theme->set_constant("title_height", "AcceptDialog", 24 * EDSCALE);
-	theme->set_font("title_font", "AcceptDialog", theme->get_font("title", "EditorFonts"));
+	theme->set_stylebox("panel", "Window", style_default);
+	theme->set_stylebox("panel_window", "Window", style_window);
+	theme->set_color("title_color", "Window", font_color);
+	theme->set_icon("close", "Window", theme->get_icon("GuiClose", "EditorIcons"));
+	theme->set_icon("close_highlight", "Window", theme->get_icon("GuiClose", "EditorIcons"));
+	theme->set_constant("close_h_ofs", "Window", 22 * EDSCALE);
+	theme->set_constant("close_v_ofs", "Window", 20 * EDSCALE);
+	theme->set_constant("title_height", "Window", 24 * EDSCALE);
+	theme->set_constant("resize_margin", "Window", 4 * EDSCALE);
+	theme->set_font("title_font", "Window", theme->get_font("title", "EditorFonts"));
 
 	// complex window, for now only Editor settings and Project settings
 	Ref<StyleBoxFlat> style_complex_window = style_window->duplicate();

+ 0 - 4
editor/filesystem_dock.cpp

@@ -2350,8 +2350,6 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) {
 }
 
 void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
-	if (get_viewport()->get_modal_stack_top())
-		return; // Ignore because of modal window.
 
 	Ref<InputEventKey> key = p_event;
 	if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
@@ -2368,8 +2366,6 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
 }
 
 void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
-	if (get_viewport()->get_modal_stack_top())
-		return; // Ignore because of modal window.
 
 	Ref<InputEventKey> key = p_event;
 	if (key.is_valid() && key->is_pressed() && !key->is_echo()) {

+ 5 - 1
editor/plugins/animation_state_machine_editor.cpp

@@ -158,7 +158,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
 				name_edit->set_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position));
 				name_edit->set_size(edit_rect.size);
 				name_edit->set_text(node_rects[i].node_name);
-				name_edit->show_modal();
+#ifndef _MSC_VER
+#warning no more show modal, so it must replaced by a popup
+#endif
+				//name_edit->show_modal();
+				name_edit->show();
 				name_edit->grab_focus();
 				name_edit->select_all();
 

+ 1 - 1
editor/plugins/canvas_item_editor_plugin.cpp

@@ -477,7 +477,7 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
 
 	Ref<InputEventKey> k = p_ev;
 
-	if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())
+	if (!is_visible_in_tree())
 		return;
 
 	if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) {

+ 1 - 1
editor/plugins/spatial_editor_plugin.cpp

@@ -5718,7 +5718,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() {
 
 void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
 
-	if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())
+	if (!is_visible_in_tree())
 		return;
 
 	snap_key_enabled = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);

+ 0 - 3
editor/scene_tree_dock.cpp

@@ -75,9 +75,6 @@ void SceneTreeDock::_input(Ref<InputEvent> p_event) {
 
 void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) {
 
-	if (get_viewport()->get_modal_stack_top())
-		return; //ignore because of modal window
-
 	if (get_focus_owner() && get_focus_owner()->is_text_field())
 		return;
 

+ 8 - 0
main/main.cpp

@@ -120,6 +120,7 @@ static int audio_driver_idx = -1;
 
 // Engine config/tools
 
+static bool single_window = false;
 static bool editor = false;
 static bool project_manager = false;
 static String locale;
@@ -303,6 +304,7 @@ void Main::print_help(const char *p_binary) {
 	OS::get_singleton()->print("  --no-window                      Disable window creation (Windows only). Useful together with --script.\n");
 	OS::get_singleton()->print("  --enable-vsync-via-compositor    When vsync is enabled, vsync via the OS' window compositor (Windows only).\n");
 	OS::get_singleton()->print("  --disable-vsync-via-compositor   Disable vsync via the OS' window compositor (Windows only).\n");
+	OS::get_singleton()->print("  --single-window                  Use a single window (no separate subwindows).\n");
 	OS::get_singleton()->print("\n");
 #endif
 
@@ -576,6 +578,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 		} else if (I->get() == "--gpu-abort") { // force windowed window
 
 			Engine::singleton->abort_on_gpu_errors = true;
+		} else if (I->get() == "--single-window") { // force single window
+
+			single_window = true;
 		} else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window
 
 			init_always_on_top = true;
@@ -1710,6 +1715,9 @@ bool Main::start() {
 		}
 #endif
 
+		if (single_window) {
+			sml->get_root()->set_embed_subwindows_hint(true);
+		}
 		ResourceLoader::add_custom_loaders();
 		ResourceSaver::add_custom_savers();
 

+ 6 - 6
platform/linuxbsd/display_server_x11.cpp

@@ -708,13 +708,13 @@ void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window
 	XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
 }
 
-void DisplayServerX11::window_set_resize_callback(const Callable &p_callable, WindowID p_window) {
+void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
 
 	_THREAD_SAFE_METHOD_
 
 	ERR_FAIL_COND(!windows.has(p_window));
 	WindowData &wd = windows[p_window];
-	wd.resize_callback = p_callable;
+	wd.rect_changed_callback = p_callable;
 }
 
 void DisplayServerX11::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
@@ -2224,12 +2224,12 @@ void DisplayServerX11::_window_changed(XEvent *event) {
 	}
 #endif
 
-	if (!wd.resize_callback.is_null()) {
-		Variant size = wd.size;
-		Variant *sizep = &size;
+	if (!wd.rect_changed_callback.is_null()) {
+		Variant rect = Rect2i(wd.im_position, wd.size);
+		Variant *rectp = &rect;
 		Variant ret;
 		Callable::CallError ce;
-		wd.resize_callback.call((const Variant **)&sizep, 1, ret, ce);
+		wd.rect_changed_callback.call((const Variant **)&rectp, 1, ret, ce);
 	}
 }
 

+ 2 - 2
platform/linuxbsd/display_server_x11.h

@@ -121,7 +121,7 @@ class DisplayServerX11 : public DisplayServer {
 		Size2i size;
 		Size2i im_position;
 		bool im_active = false;
-		Callable resize_callback;
+		Callable rect_changed_callback;
 		Callable event_callback;
 		Callable input_event_callback;
 		Callable input_text_callback;
@@ -268,7 +268,7 @@ public:
 	virtual void delete_sub_window(WindowID p_id);
 
 	virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
-	virtual void window_set_resize_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+	virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);

+ 43 - 14
platform/windows/display_server_windows.cpp

@@ -420,6 +420,10 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
 		}
 	}
 
+	ShowWindow(windows[window_id].hWnd, SW_SHOW); // Show The Window
+	SetForegroundWindow(windows[window_id].hWnd); // Slightly Higher Priority
+	SetFocus(windows[window_id].hWnd); // Sets Keyboard Focus To
+
 	return window_id;
 }
 void DisplayServerWindows::delete_sub_window(WindowID p_window) {
@@ -449,12 +453,12 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
 	windows.erase(p_window);
 }
 
-void DisplayServerWindows::window_set_resize_callback(const Callable &p_callable, WindowID p_window) {
+void DisplayServerWindows::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
 
 	_THREAD_SAFE_METHOD_
 
 	ERR_FAIL_COND(!windows.has(p_window));
-	windows[p_window].resize_callback = p_callable;
+	windows[p_window].rect_changed_callback = p_callable;
 }
 
 void DisplayServerWindows::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
@@ -757,20 +761,32 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain
 	ERR_FAIL_COND(!windows.has(p_window));
 	WindowData &wd = windows[p_window];
 
+	DWORD style = 0;
+	DWORD style_ex = WS_EX_WINDOWEDGE;
+	if (p_window == MAIN_WINDOW_ID) {
+		style_ex |= WS_EX_APPWINDOW;
+	}
+
 	if (wd.fullscreen || wd.borderless) {
-		SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
+		style = WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE;
+		if (wd.borderless) {
+			style_ex |= WS_EX_TOOLWINDOW;
+		}
 	} else {
 		if (wd.resizable) {
 			if (p_maximized) {
-				SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE);
+				style = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE;
 			} else {
-				SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
+				style = GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE;
 			}
 		} else {
-			SetWindowLongPtr(wd.hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE);
+			style = WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE;
 		}
 	}
 
+	SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
+	SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
+
 	SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
 
 	if (p_repaint) {
@@ -2208,6 +2224,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
 				int x = LOWORD(lParam);
 				int y = HIWORD(lParam);
 				windows[window_id].last_pos = Point2(x, y);
+
+				if (!windows[window_id].rect_changed_callback.is_null()) {
+
+					Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height);
+					Variant *sizep = &size;
+					Variant ret;
+					Callable::CallError ce;
+					windows[window_id].rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
+				}
 			}
 		} break;
 
@@ -2232,13 +2257,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
 				}
 			}
 
-			if (!windows[window_id].resize_callback.is_null()) {
+			if (!windows[window_id].rect_changed_callback.is_null()) {
 
-				Variant size = Size2(windows[window_id].width, windows[window_id].height);
+				Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height);
 				Variant *sizep = &size;
 				Variant ret;
 				Callable::CallError ce;
-				windows[window_id].resize_callback.call((const Variant **)&sizep, 1, ret, ce);
+				windows[window_id].rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
 			}
 
 			if (wParam == SIZE_MAXIMIZED) {
@@ -2541,9 +2566,13 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
 	DWORD dwExStyle;
 	DWORD dwStyle;
 
-	dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+	dwExStyle = WS_EX_WINDOWEDGE;
 	dwStyle = WS_OVERLAPPEDWINDOW;
 
+	if (window_id_counter == MAIN_WINDOW_ID) {
+		dwExStyle |= WS_EX_APPWINDOW;
+	}
+
 	RECT WindowRect;
 
 	WindowRect.left = p_rect.position.x;
@@ -2594,10 +2623,6 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
 
 		DragAcceptFiles(wd.hWnd, true);
 
-		ShowWindow(wd.hWnd, SW_SHOW); // Show The Window
-		SetForegroundWindow(wd.hWnd); // Slightly Higher Priority
-		SetFocus(wd.hWnd); // Sets Keyboard Focus To
-
 		// IME
 		wd.im_himc = ImmGetContext(wd.hWnd);
 		ImmReleaseContext(wd.hWnd, wd.im_himc);
@@ -2743,6 +2768,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
 		}
 	}
 
+	ShowWindow(windows[MAIN_WINDOW_ID].hWnd, SW_SHOW); // Show The Window
+	SetForegroundWindow(windows[MAIN_WINDOW_ID].hWnd); // Slightly Higher Priority
+	SetFocus(windows[MAIN_WINDOW_ID].hWnd); // Sets Keyboard Focus To
+
 #if defined(VULKAN_ENABLED)
 
 	if (rendering_driver == "vulkan") {

+ 2 - 2
platform/windows/display_server_windows.h

@@ -200,7 +200,7 @@ class DisplayServerWindows : public DisplayServer {
 
 		bool layered_window = false;
 
-		Callable resize_callback;
+		Callable rect_changed_callback;
 		Callable event_callback;
 		Callable input_event_callback;
 		Callable input_text_callback;
@@ -293,7 +293,7 @@ public:
 	virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
 	virtual void delete_sub_window(WindowID p_window);
 
-	virtual void window_set_resize_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+	virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
 
 	virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
 	virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);

+ 1 - 1
scene/2d/canvas_item.cpp

@@ -460,7 +460,7 @@ Transform2D CanvasItem::get_screen_transform() const {
 	Transform2D xform = get_global_transform_with_canvas();
 
 	Window *w = Object::cast_to<Window>(get_viewport());
-	if (w) {
+	if (w && !w->is_embedding_subwindows()) {
 		Transform2D s;
 		s.set_origin(w->get_position());
 

+ 0 - 3
scene/gui/base_button.cpp

@@ -357,9 +357,6 @@ void BaseButton::_unhandled_input(Ref<InputEvent> p_event) {
 
 	if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) {
 
-		if (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this))
-			return; //ignore because of modal window
-
 		on_action_event(p_event);
 	}
 }

+ 4 - 1
scene/gui/color_picker.cpp

@@ -620,7 +620,10 @@ void ColorPicker::_screen_pick_pressed() {
 		screen->call_deferred("connect", "hide", Callable(btn_pick, "set_pressed"), varray(false));
 	}
 	screen->raise();
-	screen->show_modal();
+#ifndef _MSC_VER
+#warning show modal no longer works, needs to be converted to a popup
+#endif
+	//screen->show_modal();
 }
 
 void ColorPicker::_focus_enter() {

+ 39 - 150
scene/gui/control.cpp

@@ -494,76 +494,54 @@ void Control::_notification(int p_notification) {
 
 			data.parent = Object::cast_to<Control>(get_parent());
 
-			if (is_set_as_toplevel()) {
-				data.SI = get_viewport()->_gui_add_subwindow_control(this);
+			Node *parent = this; //meh
+			Control *parent_control = NULL;
+			bool subwindow = false;
 
-				if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) {
-					data.theme_owner = data.parent->data.theme_owner;
-					notification(NOTIFICATION_THEME_CHANGED);
-				}
-
-			} else {
-
-				Node *parent = this; //meh
-				Control *parent_control = NULL;
-				bool subwindow = false;
-
-				while (parent) {
-
-					parent = parent->get_parent();
-
-					if (!parent)
-						break;
-
-					CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
-					if (ci && ci->is_set_as_toplevel()) {
-						subwindow = true;
-						break;
-					}
+			while (parent) {
 
-					parent_control = Object::cast_to<Control>(parent);
+				parent = parent->get_parent();
 
-					if (parent_control) {
-						break;
-					} else if (ci) {
+				if (!parent)
+					break;
 
-					} else {
-						break;
-					}
+				CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
+				if (ci && ci->is_set_as_toplevel()) {
+					subwindow = true;
+					break;
 				}
 
-				if (parent_control) {
-					//do nothing, has a parent control
-					if (data.theme.is_null() && parent_control->data.theme_owner) {
-						data.theme_owner = parent_control->data.theme_owner;
-						notification(NOTIFICATION_THEME_CHANGED);
-					}
-				} else if (subwindow) {
-					//is a subwindow (process input before other controls for that canvas)
-					data.SI = get_viewport()->_gui_add_subwindow_control(this);
-				} else {
-					//is a regular root control
-					data.RI = get_viewport()->_gui_add_root_control(this);
-				}
-
-				data.parent_canvas_item = get_parent_item();
+				parent_control = Object::cast_to<Control>(parent);
 
-				if (data.parent_canvas_item) {
+				if (parent_control) {
+					break;
+				} else if (ci) {
 
-					data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed));
 				} else {
-					//connect viewport
-					get_viewport()->connect("size_changed", callable_mp(this, &Control::_size_changed));
+					break;
 				}
 			}
 
-			/*
-			if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) {
-				data.theme_owner=data.parent->data.theme_owner;
-				notification(NOTIFICATION_THEME_CHANGED);
+			if (parent_control && !subwindow) {
+				//do nothing, has a parent control and not toplevel
+				if (data.theme.is_null() && parent_control->data.theme_owner) {
+					data.theme_owner = parent_control->data.theme_owner;
+					notification(NOTIFICATION_THEME_CHANGED);
+				}
+			} else {
+				//is a regular root control or toplevel
+				data.RI = get_viewport()->_gui_add_root_control(this);
 			}
-			*/
 
+			data.parent_canvas_item = get_parent_item();
+
+			if (data.parent_canvas_item) {
+
+				data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed));
+			} else {
+				//connect viewport
+				get_viewport()->connect("size_changed", callable_mp(this, &Control::_size_changed));
+			}
 		} break;
 		case NOTIFICATION_EXIT_CANVAS: {
 
@@ -576,16 +554,6 @@ void Control::_notification(int p_notification) {
 				get_viewport()->disconnect("size_changed", callable_mp(this, &Control::_size_changed));
 			}
 
-			if (data.MI) {
-				get_viewport()->_gui_remove_modal_control(data.MI);
-				data.MI = NULL;
-			}
-
-			if (data.SI) {
-				get_viewport()->_gui_remove_subwindow_control(data.SI);
-				data.SI = NULL;
-			}
-
 			if (data.RI) {
 				get_viewport()->_gui_remove_root_control(data.RI);
 				data.RI = NULL;
@@ -608,9 +576,6 @@ void Control::_notification(int p_notification) {
 				data.parent->update();
 			update();
 
-			if (data.SI) {
-				get_viewport()->_gui_set_subwindow_order_dirty();
-			}
 			if (data.RI) {
 				get_viewport()->_gui_set_root_order_dirty();
 			}
@@ -652,10 +617,6 @@ void Control::_notification(int p_notification) {
 			minimum_size_changed();
 			update();
 		} break;
-		case NOTIFICATION_MODAL_CLOSE: {
-
-			emit_signal("modal_closed");
-		} break;
 		case NOTIFICATION_VISIBILITY_CHANGED: {
 
 			if (!is_visible_in_tree()) {
@@ -663,10 +624,6 @@ void Control::_notification(int p_notification) {
 				if (get_viewport() != NULL)
 					get_viewport()->_gui_hid_control(this);
 
-				if (is_inside_tree()) {
-					_modal_stack_remove();
-				}
-
 				//remove key focus
 				//remove modalness
 			} else {
@@ -790,19 +747,6 @@ void Control::set_drag_preview(Control *p_control) {
 	get_viewport()->_gui_set_drag_preview(this, p_control);
 }
 
-bool Control::is_window_modal_on_top() const {
-
-	if (!is_inside_tree())
-		return false;
-
-	return get_viewport()->_gui_is_modal_on_top(this);
-}
-
-uint64_t Control::get_modal_frame() const {
-
-	return data.modal_frame;
-}
-
 Size2 Control::get_minimum_size() const {
 
 	ScriptInstance *si = const_cast<Control *>(this)->get_script_instance();
@@ -1720,7 +1664,7 @@ Point2 Control::get_screen_position() const {
 	ERR_FAIL_COND_V(!is_inside_tree(), Point2());
 	Point2 global_pos = get_global_position();
 	Window *w = Object::cast_to<Window>(get_viewport());
-	if (w) {
+	if (w && !w->is_embedding_subwindows()) {
 		global_pos += w->get_position();
 	}
 
@@ -1828,7 +1772,7 @@ Rect2 Control::get_screen_rect() const {
 	Rect2 r(get_global_position(), get_size());
 
 	Window *w = Object::cast_to<Window>(get_viewport());
-	if (w) {
+	if (w && !w->is_embedding_subwindows()) {
 		r.position += w->get_position();
 	}
 
@@ -2021,7 +1965,7 @@ Control *Control::find_next_valid_focus() const {
 					next_child = const_cast<Control *>(this);
 					while (next_child) {
 
-						if (next_child->data.SI || next_child->data.RI)
+						if (next_child->data.RI)
 							break;
 						next_child = next_child->get_parent_control();
 					}
@@ -2164,41 +2108,6 @@ bool Control::is_toplevel_control() const {
 	return is_inside_tree() && (!data.parent_canvas_item && !data.RI && is_set_as_toplevel());
 }
 
-void Control::show_modal(bool p_exclusive) {
-
-	ERR_FAIL_COND(!is_inside_tree());
-	ERR_FAIL_COND(!data.SI);
-
-	if (is_visible_in_tree())
-		hide();
-
-	ERR_FAIL_COND(data.MI != NULL);
-	show();
-	raise();
-	data.modal_exclusive = p_exclusive;
-	data.MI = get_viewport()->_gui_show_modal(this);
-	data.modal_frame = Engine::get_singleton()->get_frames_drawn();
-}
-
-void Control::_modal_set_prev_focus_owner(ObjectID p_prev) {
-	data.modal_prev_focus_owner = p_prev;
-}
-
-void Control::_modal_stack_remove() {
-
-	ERR_FAIL_COND(!is_inside_tree());
-
-	if (!data.MI)
-		return;
-
-	List<Control *>::Element *element = data.MI;
-	data.MI = NULL;
-
-	get_viewport()->_gui_remove_from_modal_stack(element, data.modal_prev_focus_owner);
-
-	data.modal_prev_focus_owner = ObjectID();
-}
-
 void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) {
 
 	Control *c = Object::cast_to<Control>(p_at);
@@ -2444,8 +2353,6 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
 
 		Control *c = Object::cast_to<Control>(base);
 		if (c) {
-			if (c->data.SI)
-				break;
 			if (c->data.RI)
 				break;
 		}
@@ -2515,7 +2422,7 @@ void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, con
 
 		Node *child = p_at->get_child(i);
 		Control *childc = Object::cast_to<Control>(child);
-		if (childc && childc->data.SI)
+		if (childc && childc->data.RI)
 			continue; //subwindow, ignore
 		_window_find_focus_neighbour(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest);
 	}
@@ -2609,16 +2516,6 @@ Control::MouseFilter Control::get_mouse_filter() const {
 	return data.mouse_filter;
 }
 
-void Control::set_pass_on_modal_close_click(bool p_pass_on) {
-
-	data.pass_on_modal_close_click = p_pass_on;
-}
-
-bool Control::pass_on_modal_close_click() const {
-
-	return data.pass_on_modal_close_click;
-}
-
 Control *Control::get_focus_owner() const {
 
 	ERR_FAIL_COND_V(!is_inside_tree(), NULL);
@@ -2712,7 +2609,7 @@ Control *Control::get_root_parent_control() const {
 		if (c) {
 			root = c;
 
-			if (c->data.RI || c->data.MI || c->is_toplevel_control())
+			if (c->data.RI || c->is_toplevel_control())
 				break;
 		}
 
@@ -2864,7 +2761,6 @@ void Control::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_global_position"), &Control::get_global_position);
 	ClassDB::bind_method(D_METHOD("get_rect"), &Control::get_rect);
 	ClassDB::bind_method(D_METHOD("get_global_rect"), &Control::get_global_rect);
-	ClassDB::bind_method(D_METHOD("show_modal", "exclusive"), &Control::show_modal, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("set_focus_mode", "mode"), &Control::set_focus_mode);
 	ClassDB::bind_method(D_METHOD("get_focus_mode"), &Control::get_focus_mode);
 	ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus);
@@ -3024,7 +2920,6 @@ void Control::_bind_methods() {
 	BIND_CONSTANT(NOTIFICATION_FOCUS_ENTER);
 	BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT);
 	BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
-	BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE);
 	BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN);
 	BIND_CONSTANT(NOTIFICATION_SCROLL_END);
 
@@ -3093,7 +2988,6 @@ void Control::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("focus_exited"));
 	ADD_SIGNAL(MethodInfo("size_flags_changed"));
 	ADD_SIGNAL(MethodInfo("minimum_size_changed"));
-	ADD_SIGNAL(MethodInfo("modal_closed"));
 	ADD_SIGNAL(MethodInfo("theme_changed"));
 
 	BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_point", PropertyInfo(Variant::VECTOR2, "point")));
@@ -3103,14 +2997,10 @@ Control::Control() {
 	data.parent = NULL;
 
 	data.mouse_filter = MOUSE_FILTER_STOP;
-	data.pass_on_modal_close_click = true;
 
-	data.SI = NULL;
-	data.MI = NULL;
 	data.RI = NULL;
 	data.theme_owner = NULL;
 	data.theme_owner_window = NULL;
-	data.modal_exclusive = false;
 	data.default_cursor = CURSOR_ARROW;
 	data.h_size_flags = SIZE_FILL;
 	data.v_size_flags = SIZE_FILL;
@@ -3119,7 +3009,6 @@ Control::Control() {
 	data.parent_canvas_item = NULL;
 	data.scale = Vector2(1, 1);
 
-	data.modal_frame = 0;
 	data.block_minimum_size_adjust = false;
 	data.disable_visibility_clip = false;
 	data.h_grow = GROW_DIRECTION_END;

+ 0 - 19
scene/gui/control.h

@@ -168,8 +168,6 @@ private:
 		float expand;
 		Point2 custom_minimum_size;
 
-		bool pass_on_modal_close_click;
-
 		MouseFilter mouse_filter;
 
 		bool clip_contents;
@@ -179,22 +177,16 @@ private:
 
 		Control *parent;
 		ObjectID drag_owner;
-		bool modal_exclusive;
-		uint64_t modal_frame; //frame used to put something as modal
 		Ref<Theme> theme;
 		Control *theme_owner;
 		Window *theme_owner_window;
 		String tooltip;
 		CursorShape default_cursor;
 
-		List<Control *>::Element *MI; //modal item
-		List<Control *>::Element *SI;
 		List<Control *>::Element *RI;
 
 		CanvasItem *parent_canvas_item;
 
-		ObjectID modal_prev_focus_owner;
-
 		NodePath focus_neighbour[4];
 		NodePath focus_next;
 		NodePath focus_prev;
@@ -240,8 +232,6 @@ private:
 	Transform2D _get_internal_transform() const;
 
 	friend class Viewport;
-	void _modal_stack_remove();
-	void _modal_set_prev_focus_owner(ObjectID p_prev);
 
 	void _update_minimum_size_cache();
 	friend class Window;
@@ -293,7 +283,6 @@ public:
 		NOTIFICATION_FOCUS_ENTER = 43,
 		NOTIFICATION_FOCUS_EXIT = 44,
 		NOTIFICATION_THEME_CHANGED = 45,
-		NOTIFICATION_MODAL_CLOSE = 46,
 		NOTIFICATION_SCROLL_BEGIN = 47,
 		NOTIFICATION_SCROLL_END = 48,
 
@@ -341,9 +330,6 @@ public:
 	void set_custom_minimum_size(const Size2 &p_custom);
 	Size2 get_custom_minimum_size() const;
 
-	bool is_window_modal_on_top() const;
-	uint64_t get_modal_frame() const; //frame in which this was made modal
-
 	Control *get_parent_control() const;
 
 	/* POSITIONING */
@@ -398,8 +384,6 @@ public:
 	void set_scale(const Vector2 &p_scale);
 	Vector2 get_scale() const;
 
-	void show_modal(bool p_exclusive = false);
-
 	void set_theme(const Ref<Theme> &p_theme);
 	Ref<Theme> get_theme() const;
 
@@ -438,9 +422,6 @@ public:
 	void set_mouse_filter(MouseFilter p_filter);
 	MouseFilter get_mouse_filter() const;
 
-	void set_pass_on_modal_close_click(bool p_pass_on);
-	bool pass_on_modal_close_click() const;
-
 	/* SKINNING */
 
 	void add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon);

+ 9 - 5
scene/gui/menu_button.cpp

@@ -43,20 +43,24 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
 		if (!get_parent() || !is_visible_in_tree() || is_disabled())
 			return;
 
-		bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this));
-
-		if (popup->activate_item_by_event(p_event, global_only))
+		//bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this));
+		//if (popup->activate_item_by_event(p_event, global_only))
+		//	accept_event();
+		if (popup->activate_item_by_event(p_event, false))
 			accept_event();
 	}
 }
 
 void MenuButton::pressed() {
 
-	emit_signal("about_to_popup");
 	Size2 size = get_size();
 
 	Point2 gp = get_screen_position();
-	popup->set_position(gp + Size2(0, size.height * get_global_transform().get_scale().y));
+
+	gp.y += get_size().y;
+
+	popup->set_position(gp);
+
 	popup->set_size(Size2(size.width, 0));
 	popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), get_size()));
 	popup->popup();

+ 7 - 4
scene/gui/popup_menu.cpp

@@ -163,7 +163,7 @@ void PopupMenu::_activate_submenu(int over) {
 	Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y);
 	Size2 size = pm->get_size();
 	// fix pos
-	if (pos.x + size.width > get_screen_rect().size.width)
+	if (pos.x + size.width > get_parent_rect().size.width)
 		pos.x = p.x - size.width;
 
 	pm->set_position(pos);
@@ -203,7 +203,7 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
 		dy = MIN(dy, limit);
 	} else if (dy < 0) {
 		const float global_bottom = get_position().y + get_size().y;
-		const float viewport_height = get_screen_rect().size.y;
+		const float viewport_height = get_parent_rect().size.y;
 		const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0;
 		dy = -MIN(-dy, limit);
 	}
@@ -295,7 +295,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
 
 			case BUTTON_WHEEL_DOWN: {
 
-				if (get_position().y + get_size().y > get_screen_rect().size.y) {
+				if (get_position().y + get_size().y > get_parent_rect().size.y) {
 					_scroll(-b->get_factor(), b->get_position());
 				}
 			} break;
@@ -382,7 +382,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
 
 	Ref<InputEventPanGesture> pan_gesture = p_event;
 	if (pan_gesture.is_valid()) {
-		if (get_position().y + get_size().y > get_screen_rect().size.y || get_position().y < 0) {
+		if (get_position().y + get_size().y > get_parent_rect().size.y || get_position().y < 0) {
 			_scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
 		}
 	}
@@ -591,6 +591,9 @@ void PopupMenu::_notification(int p_what) {
 
 			initial_button_mask = InputFilter::get_singleton()->get_mouse_button_mask();
 			during_grabbed_click = (bool)initial_button_mask;
+		} break;
+		case NOTIFICATION_WM_SIZE_CHANGED: {
+
 		} break;
 		case NOTIFICATION_VISIBILITY_CHANGED: {
 

+ 8 - 3
scene/gui/tree.cpp

@@ -2819,7 +2819,10 @@ bool Tree::edit_selected() {
 
 			value_editor->set_position(textedpos + Point2i(0, text_editor->get_size().height));
 			value_editor->set_size(Size2(rect.size.width, 1));
-			value_editor->show_modal();
+#ifndef _MSC_VER
+#warning show modal no longer works, need to replace by a popup
+#endif
+			value_editor->show();
 			updating_value_editor = true;
 			value_editor->set_min(c.min);
 			value_editor->set_max(c.max);
@@ -2828,8 +2831,10 @@ bool Tree::edit_selected() {
 			value_editor->set_exp_ratio(c.expr);
 			updating_value_editor = false;
 		}
-
-		text_editor->show_modal();
+#ifndef _MSC_VER
+#warning show modal no longer works, need to replace by a popup
+#endif
+		text_editor->show();
 		text_editor->grab_focus();
 		return true;
 	}

+ 506 - 254
scene/main/viewport.cpp

@@ -187,6 +187,7 @@ public:
 Viewport::GUI::GUI() {
 
 	embed_subwindows_hint = false;
+	embedding_subwindows = false;
 
 	dragging = false;
 	mouse_focus = NULL;
@@ -198,8 +199,6 @@ Viewport::GUI::GUI() {
 	tooltip = NULL;
 	tooltip_popup = NULL;
 	tooltip_label = NULL;
-	subwindow_visibility_dirty = false;
-	subwindow_order_dirty = false;
 }
 
 /////////////////////////////////////
@@ -236,6 +235,180 @@ void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *
 	physics_last_id = id;
 }
 
+void Viewport::_sub_window_update_order() {
+
+	for (int i = 0; i < gui.sub_windows.size(); i++) {
+		VS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i);
+	}
+}
+
+void Viewport::_sub_window_register(Window *p_window) {
+
+	ERR_FAIL_COND(!is_inside_tree());
+	for (int i = 0; i < gui.sub_windows.size(); i++) {
+		ERR_FAIL_COND(gui.sub_windows[i].window == p_window);
+	}
+
+	if (gui.sub_windows.size() == 0) {
+		subwindow_canvas = VS::get_singleton()->canvas_create();
+		VS::get_singleton()->viewport_attach_canvas(viewport, subwindow_canvas);
+		VS::get_singleton()->viewport_set_canvas_stacking(viewport, subwindow_canvas, SUBWINDOW_CANVAS_LAYER, 0);
+	}
+	SubWindow sw;
+	sw.canvas_item = VS::get_singleton()->canvas_item_create();
+	VS::get_singleton()->canvas_item_set_parent(sw.canvas_item, subwindow_canvas);
+	sw.window = p_window;
+	gui.sub_windows.push_back(sw);
+
+	_sub_window_grab_focus(p_window);
+
+	VisualServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, viewport);
+}
+
+void Viewport::_sub_window_update(Window *p_window) {
+
+	int index = -1;
+	for (int i = 0; i < gui.sub_windows.size(); i++) {
+		if (gui.sub_windows[i].window == p_window) {
+			index = i;
+			break;
+		}
+	}
+
+	ERR_FAIL_COND(index == -1);
+
+	const SubWindow &sw = gui.sub_windows[index];
+
+	Transform2D pos;
+	pos.set_origin(p_window->get_position());
+	VS::get_singleton()->canvas_item_clear(sw.canvas_item);
+	Rect2i r = Rect2i(p_window->get_position(), sw.window->get_size());
+
+	if (!p_window->get_flag(Window::FLAG_BORDERLESS)) {
+		Ref<StyleBox> panel = p_window->get_theme_stylebox("panel_window");
+		panel->draw(sw.canvas_item, r);
+
+		// Draw the title bar text.
+		Ref<Font> title_font = p_window->get_theme_font("title_font");
+		Color title_color = p_window->get_theme_color("title_color");
+		int title_height = p_window->get_theme_constant("title_height");
+		int font_height = title_font->get_height() - title_font->get_descent() * 2;
+		int x = (r.size.width - title_font->get_string_size(p_window->get_title()).x) / 2;
+		int y = (-title_height + font_height) / 2;
+
+		int close_h_ofs = p_window->get_theme_constant("close_h_ofs");
+		int close_v_ofs = p_window->get_theme_constant("close_v_ofs");
+
+		title_font->draw(sw.canvas_item, r.position + Point2(x, y), p_window->get_title(), title_color, r.size.width - panel->get_minimum_size().x - close_h_ofs);
+
+		bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside;
+
+		Ref<Texture2D> close_icon = p_window->get_theme_icon(hl ? "close_highlight" : "close");
+		close_icon->draw(sw.canvas_item, r.position + Vector2(r.size.width - close_h_ofs, -close_v_ofs));
+	}
+
+	VS::get_singleton()->canvas_item_add_texture_rect(sw.canvas_item, r, sw.window->get_texture()->get_rid());
+}
+
+void Viewport::_sub_window_grab_focus(Window *p_window) {
+
+	if (p_window == nullptr) {
+		//release current focus
+		if (gui.subwindow_focused) {
+			gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+			gui.subwindow_focused = nullptr;
+			gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+		}
+
+		Window *this_window = Object::cast_to<Window>(this);
+		if (this_window) {
+			this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+		}
+
+		return;
+	}
+	int index = -1;
+	for (int i = 0; i < gui.sub_windows.size(); i++) {
+		if (gui.sub_windows[i].window == p_window) {
+			index = i;
+			break;
+		}
+	}
+
+	ERR_FAIL_COND(index == -1);
+
+	if (gui.subwindow_focused) {
+		if (gui.subwindow_focused == p_window) {
+			return; //nothing to do
+		}
+		gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+		gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+	} else {
+		Window *this_window = Object::cast_to<Window>(this);
+		if (this_window) {
+			this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+		}
+	}
+
+	Window *old_focus = gui.subwindow_focused;
+
+	gui.subwindow_focused = p_window;
+
+	gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+
+	{ //move to foreground
+		SubWindow sw = gui.sub_windows[index];
+		gui.sub_windows.remove(index);
+		gui.sub_windows.push_back(sw);
+		index = gui.sub_windows.size() - 1;
+		_sub_window_update_order();
+	}
+
+	if (old_focus) {
+		_sub_window_update(old_focus);
+	}
+
+	_sub_window_update(p_window);
+}
+
+void Viewport::_sub_window_remove(Window *p_window) {
+
+	for (int i = 0; i < gui.sub_windows.size(); i++) {
+		if (gui.sub_windows[i].window == p_window) {
+			VS::get_singleton()->free(gui.sub_windows[i].canvas_item);
+			gui.sub_windows.remove(i);
+			break;
+		}
+	}
+
+	if (gui.sub_windows.size() == 0) {
+		VS::get_singleton()->free(subwindow_canvas);
+		subwindow_canvas = RID();
+	}
+
+	if (gui.subwindow_focused == p_window) {
+		Window *parent_visible = p_window->get_parent_visible_window();
+
+		gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+
+		gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+
+		if (parent_visible && parent_visible != this) {
+
+			gui.subwindow_focused = parent_visible;
+			gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+		} else {
+			gui.subwindow_focused = nullptr;
+			Window *this_window = Object::cast_to<Window>(this);
+			if (this_window) {
+				this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+			}
+		}
+	}
+
+	VisualServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID());
+}
+
 void Viewport::_own_world_changed() {
 	ERR_FAIL_COND(world.is_null());
 	ERR_FAIL_COND(own_world.is_null());
@@ -263,6 +436,8 @@ void Viewport::_notification(int p_what) {
 
 		case NOTIFICATION_ENTER_TREE: {
 
+			gui.embedding_subwindows = gui.embed_subwindows_hint;
+
 			if (get_parent()) {
 				parent = get_parent()->get_viewport();
 				VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid());
@@ -297,7 +472,6 @@ void Viewport::_notification(int p_what) {
 				//VisualServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
 			}
 
-			VS::get_singleton()->viewport_set_active(viewport, true);
 		} break;
 		case NOTIFICATION_READY: {
 #ifndef _3D_DISABLED
@@ -358,6 +532,7 @@ void Viewport::_notification(int p_what) {
 			remove_from_group("_viewports");
 
 			VS::get_singleton()->viewport_set_active(viewport, false);
+			VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, RID());
 
 		} break;
 		case NOTIFICATION_INTERNAL_PROCESS: {
@@ -1318,25 +1493,16 @@ Transform2D Viewport::_get_input_pre_xform() const {
 	return pre_xf;
 }
 
-Vector2 Viewport::_get_window_offset() const {
-
-	if (get_parent() && get_parent()->has_method("get_global_position")) {
-		return get_parent()->call("get_global_position");
-	}
-	return Vector2();
-}
-
 Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
 
-	Vector2 vp_ofs = _get_window_offset();
 	Transform2D ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
 
-	return ev->xformed_by(ai, -vp_ofs);
+	return ev->xformed_by(ai);
 }
 
 Vector2 Viewport::get_mouse_position() const {
 
-	return (get_final_transform().affine_inverse() * _get_input_pre_xform()).xform(InputFilter::get_singleton()->get_mouse_position() - _get_window_offset());
+	return gui.last_mouse_pos;
 }
 
 void Viewport::warp_mouse(const Vector2 &p_pos) {
@@ -1345,40 +1511,6 @@ void Viewport::warp_mouse(const Vector2 &p_pos) {
 	InputFilter::get_singleton()->warp_mouse_position(gpos);
 }
 
-void Viewport::_gui_prepare_subwindows() {
-
-	if (gui.subwindow_visibility_dirty) {
-
-		gui.subwindows.clear();
-		for (List<Control *>::Element *E = gui.all_known_subwindows.front(); E; E = E->next()) {
-			if (E->get()->is_visible_in_tree()) {
-				gui.subwindows.push_back(E->get());
-			}
-		}
-
-		gui.subwindow_visibility_dirty = false;
-		gui.subwindow_order_dirty = true;
-	}
-
-	_gui_sort_subwindows();
-}
-
-void Viewport::_gui_sort_subwindows() {
-
-	if (!gui.subwindow_order_dirty)
-		return;
-
-	gui.modal_stack.sort_custom<Control::CComparator>();
-	gui.subwindows.sort_custom<Control::CComparator>();
-
-	gui.subwindow_order_dirty = false;
-}
-
-void Viewport::_gui_sort_modal_stack() {
-
-	gui.modal_stack.sort_custom<Control::CComparator>();
-}
-
 void Viewport::_gui_sort_roots() {
 
 	if (!gui.roots_order_dirty)
@@ -1581,26 +1713,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) {
 }
 Control *Viewport::_gui_find_control(const Point2 &p_global) {
 
-	_gui_prepare_subwindows();
-
-	for (List<Control *>::Element *E = gui.subwindows.back(); E; E = E->prev()) {
-
-		Control *sw = E->get();
-		if (!sw->is_visible_in_tree())
-			continue;
-
-		Transform2D xform;
-		CanvasItem *pci = sw->get_parent_item();
-		if (pci)
-			xform = pci->get_global_transform_with_canvas();
-		else
-			xform = sw->get_canvas_transform();
-
-		Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform);
-		if (ret)
-			return ret;
-	}
-
+	//aca va subwindows
 	_gui_sort_roots();
 
 	for (List<Control *>::Element *E = gui.roots.back(); E; E = E->prev()) {
@@ -1629,8 +1742,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
 	if (Object::cast_to<Viewport>(p_node))
 		return NULL;
 
-	//subwindows first!!
-
 	if (!p_node->is_visible()) {
 		//return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform);
 		return NULL; //canvas item hidden, discard
@@ -1735,39 +1846,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 
 				bool is_handled = false;
 
-				_gui_sort_modal_stack();
-				while (!gui.modal_stack.empty()) {
-
-					Control *top = gui.modal_stack.back()->get();
-					Vector2 pos2 = top->get_global_transform_with_canvas().affine_inverse().xform(mpos);
-					if (!top->has_point(pos2)) {
-
-						if (top->data.modal_exclusive || top->data.modal_frame == Engine::get_singleton()->get_frames_drawn()) {
-							//cancel event, sorry, modal exclusive EATS UP ALL
-							//alternative, you can't pop out a window the same frame it was made modal (fixes many issues)
-							set_input_as_handled();
-
-							return; // no one gets the event if exclusive NO ONE
-						}
-
-						if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN || mb->get_button_index() == BUTTON_WHEEL_LEFT || mb->get_button_index() == BUTTON_WHEEL_RIGHT) {
-							//cancel scroll wheel events, only clicks should trigger focus changes.
-							set_input_as_handled();
-							return;
-						}
-
-						top->notification(Control::NOTIFICATION_MODAL_CLOSE);
-						top->_modal_stack_remove();
-						top->hide();
-
-						if (!top->pass_on_modal_close_click()) {
-							is_handled = true;
-						}
-					} else {
-						break;
-					}
-				}
-
 				if (is_handled) {
 					set_input_as_handled();
 					return;
@@ -1990,15 +2068,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 			over = _gui_find_control(mpos);
 		}
 
-		if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) {
-
-			Control *top = gui.modal_stack.back()->get();
-
-			if (over != top && !top->is_a_parent_of(over)) {
-				over = NULL; //nothing can be found outside the modal stack
-			}
-		}
-
 		if (over != gui.mouse_over) {
 
 			if (gui.mouse_over) {
@@ -2039,11 +2108,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 
 			bool can_tooltip = true;
 
-			if (!gui.modal_stack.empty()) {
-				if (gui.modal_stack.back()->get() != over && !gui.modal_stack.back()->get()->is_a_parent_of(over))
-					can_tooltip = false;
-			}
-
 			bool is_tooltip_shown = false;
 
 			if (gui.tooltip_popup) {
@@ -2122,14 +2186,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 			Control *over = _gui_find_control(pos);
 			if (over) {
 
-				if (!gui.modal_stack.empty()) {
-
-					Control *top = gui.modal_stack.back()->get();
-					if (over != top && !top->is_a_parent_of(over)) {
-
-						return;
-					}
-				}
 				if (over->can_process()) {
 
 					touch_event = touch_event->xformed_by(Transform2D()); //make a copy
@@ -2195,14 +2251,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 		}
 		if (over) {
 
-			if (!gui.modal_stack.empty()) {
-
-				Control *top = gui.modal_stack.back()->get();
-				if (over != top && !top->is_a_parent_of(over)) {
-
-					return;
-				}
-			}
 			if (over->can_process()) {
 
 				Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
@@ -2246,21 +2294,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
 			}
 		}
 
-		if (p_event->is_pressed() && p_event->is_action("ui_cancel") && !gui.modal_stack.empty()) {
-
-			_gui_sort_modal_stack();
-			Control *top = gui.modal_stack.back()->get();
-			if (!top->data.modal_exclusive) {
-
-				top->notification(Control::NOTIFICATION_MODAL_CLOSE);
-				top->_modal_stack_remove();
-				top->hide();
-				// Close modal, set input as handled
-				set_input_as_handled();
-				return;
-			}
-		}
-
 		Control *from = gui.key_focus ? gui.key_focus : NULL; //hmm
 
 		//keyboard focus
@@ -2319,61 +2352,10 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
 	return gui.roots.push_back(p_control);
 }
 
-List<Control *>::Element *Viewport::_gui_add_subwindow_control(Control *p_control) {
-
-	p_control->connect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed));
-
-	if (p_control->is_visible_in_tree()) {
-		gui.subwindow_order_dirty = true;
-		gui.subwindows.push_back(p_control);
-	}
-
-	return gui.all_known_subwindows.push_back(p_control);
-}
-
-void Viewport::_gui_set_subwindow_order_dirty() {
-	gui.subwindow_order_dirty = true;
-}
-
 void Viewport::_gui_set_root_order_dirty() {
 	gui.roots_order_dirty = true;
 }
 
-void Viewport::_gui_remove_modal_control(List<Control *>::Element *MI) {
-
-	gui.modal_stack.erase(MI);
-}
-
-void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner) {
-
-	//transfer the focus stack to the next
-
-	List<Control *>::Element *next = MI->next();
-
-	gui.modal_stack.erase(MI);
-
-	if (p_prev_focus_owner.is_valid()) {
-
-		// for previous window in stack, pass the focus so it feels more
-		// natural
-
-		if (!next) { //top of stack
-
-			Object *pfo = ObjectDB::get_instance(p_prev_focus_owner);
-			Control *pfoc = Object::cast_to<Control>(pfo);
-			if (!pfoc)
-				return;
-
-			if (!pfoc->is_inside_tree() || !pfoc->is_visible_in_tree())
-				return;
-			pfoc->grab_focus();
-		} else {
-
-			next->get()->_modal_set_prev_focus_owner(p_prev_focus_owner);
-		}
-	}
-}
-
 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.");
@@ -2410,21 +2392,6 @@ void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) {
 	gui.roots.erase(RI);
 }
 
-void Viewport::_gui_remove_subwindow_control(List<Control *>::Element *SI) {
-
-	ERR_FAIL_COND(!SI);
-
-	Control *control = SI->get();
-
-	control->disconnect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed));
-
-	List<Control *>::Element *E = gui.subwindows.find(control);
-	if (E)
-		gui.subwindows.erase(E);
-
-	gui.all_known_subwindows.erase(SI);
-}
-
 void Viewport::_gui_unfocus_control(Control *p_control) {
 
 	if (gui.key_focus == p_control) {
@@ -2485,11 +2452,6 @@ void Viewport::_gui_remove_focus() {
 	}
 }
 
-bool Viewport::_gui_is_modal_on_top(const Control *p_control) {
-
-	return (gui.modal_stack.size() && gui.modal_stack.back()->get() == p_control);
-}
-
 bool Viewport::_gui_control_has_focus(const Control *p_control) {
 
 	return gui.key_focus == p_control;
@@ -2561,22 +2523,6 @@ void Viewport::_drop_physics_mouseover() {
 #endif
 }
 
-List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
-
-	List<Control *>::Element *node = gui.modal_stack.push_back(p_control);
-	if (gui.key_focus)
-		p_control->_modal_set_prev_focus_owner(gui.key_focus->get_instance_id());
-	else
-		p_control->_modal_set_prev_focus_owner(ObjectID());
-
-	if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
-
-		_drop_mouse_focus();
-	}
-
-	return node;
-}
-
 Control *Viewport::_gui_get_focus_owner() {
 
 	return gui.key_focus;
@@ -2647,10 +2593,317 @@ void Viewport::_post_gui_grab_click_focus() {
 
 void Viewport::input_text(const String &p_text) {
 
+	if (gui.subwindow_focused) {
+		gui.subwindow_focused->input_text(p_text);
+		return;
+	}
+
 	if (gui.key_focus) {
 		gui.key_focus->call("set_text", p_text);
 	}
 }
+Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point) {
+
+	if (p_subwindow->get_flag(Window::FLAG_BORDERLESS)) {
+		return SUB_WINDOW_RESIZE_DISABLED;
+	}
+
+	Rect2i r = Rect2i(p_subwindow->get_position(), p_subwindow->get_size());
+
+	int title_height = p_subwindow->get_theme_constant("title_height");
+
+	r.position.y -= title_height;
+	r.size.y += title_height;
+
+	if (r.has_point(p_point)) {
+		return SUB_WINDOW_RESIZE_DISABLED; //it's inside, so no resize
+	}
+
+	int dist_x = p_point.x < r.position.x ? (p_point.x - r.position.x) : (p_point.x > (r.position.x + r.size.x) ? (p_point.x - (r.position.x + r.size.x)) : 0);
+	int dist_y = p_point.y < r.position.y ? (p_point.y - r.position.y) : (p_point.y > (r.position.y + r.size.y) ? (p_point.y - (r.position.y + r.size.y)) : 0);
+
+	int limit = p_subwindow->get_theme_constant("resize_margin");
+
+	if (ABS(dist_x) > limit) {
+		return SUB_WINDOW_RESIZE_DISABLED;
+	}
+
+	if (ABS(dist_y) > limit) {
+		return SUB_WINDOW_RESIZE_DISABLED;
+	}
+
+	if (dist_x < 0 && dist_y < 0) {
+		return SUB_WINDOW_RESIZE_TOP_LEFT;
+	}
+
+	if (dist_x == 0 && dist_y < 0) {
+		return SUB_WINDOW_RESIZE_TOP;
+	}
+
+	if (dist_x > 0 && dist_y < 0) {
+		return SUB_WINDOW_RESIZE_TOP_RIGHT;
+	}
+
+	if (dist_x < 0 && dist_y == 0) {
+		return SUB_WINDOW_RESIZE_LEFT;
+	}
+
+	if (dist_x > 0 && dist_y == 0) {
+		return SUB_WINDOW_RESIZE_RIGHT;
+	}
+
+	if (dist_x < 0 && dist_y > 0) {
+		return SUB_WINDOW_RESIZE_BOTTOM_LEFT;
+	}
+
+	if (dist_x == 0 && dist_y > 0) {
+		return SUB_WINDOW_RESIZE_BOTTOM;
+	}
+
+	if (dist_x > 0 && dist_y > 0) {
+		return SUB_WINDOW_RESIZE_BOTTOM_RIGHT;
+	}
+
+	return SUB_WINDOW_RESIZE_DISABLED;
+}
+bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
+
+	if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
+
+		ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false);
+
+		Ref<InputEventMouseButton> mb = p_event;
+		if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+
+			if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
+				if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) {
+					//close window
+					gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST);
+				}
+			}
+			gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+			if (gui.subwindow_focused != nullptr) { //may have been erased
+				_sub_window_update(gui.subwindow_focused);
+			}
+		}
+
+		Ref<InputEventMouseMotion> mm = p_event;
+		if (mm.is_valid()) {
+
+			if (gui.subwindow_drag == SUB_WINDOW_DRAG_MOVE) {
+				Vector2 diff = mm->get_position() - gui.subwindow_drag_from;
+				Rect2i new_rect(gui.subwindow_drag_pos + diff, gui.subwindow_focused->get_size());
+				gui.subwindow_focused->_rect_changed_callback(new_rect);
+			}
+			if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
+				gui.subwindow_drag_close_inside = gui.subwindow_drag_close_rect.has_point(mm->get_position());
+			}
+			if (gui.subwindow_drag == SUB_WINDOW_DRAG_RESIZE) {
+				Vector2i diff = mm->get_position() - gui.subwindow_drag_from;
+				Size2i min_size = gui.subwindow_focused->get_min_size();
+				if (gui.subwindow_focused->is_wrapping_controls()) {
+					Size2i cms = gui.subwindow_focused->get_contents_minimum_size();
+					min_size.x = MAX(cms.x, min_size.x);
+					min_size.y = MAX(cms.y, min_size.y);
+				}
+				min_size.x = MAX(min_size.x, 1);
+				min_size.y = MAX(min_size.y, 1);
+
+				Rect2i r = gui.subwindow_resize_from_rect;
+
+				Size2i limit = r.size - min_size;
+
+				switch (gui.subwindow_resize_mode) {
+					case SUB_WINDOW_RESIZE_TOP_LEFT: {
+
+						diff.x = MIN(diff.x, limit.x);
+						diff.y = MIN(diff.y, limit.y);
+						r.position += diff;
+						r.size -= diff;
+					} break;
+					case SUB_WINDOW_RESIZE_TOP: {
+						diff.x = 0;
+						diff.y = MIN(diff.y, limit.y);
+						r.position += diff;
+						r.size -= diff;
+					} break;
+					case SUB_WINDOW_RESIZE_TOP_RIGHT: {
+						diff.x = MAX(diff.x, -limit.x);
+						diff.y = MIN(diff.y, limit.y);
+						r.position.y += diff.y;
+						r.size.y -= diff.y;
+						r.size.x += diff.x;
+					} break;
+					case SUB_WINDOW_RESIZE_LEFT: {
+						diff.x = MIN(diff.x, limit.x);
+						diff.y = 0;
+						r.position += diff;
+						r.size -= diff;
+
+					} break;
+					case SUB_WINDOW_RESIZE_RIGHT: {
+						diff.x = MAX(diff.x, -limit.x);
+						r.size.x += diff.x;
+					} break;
+					case SUB_WINDOW_RESIZE_BOTTOM_LEFT: {
+						diff.x = MIN(diff.x, limit.x);
+						diff.y = MAX(diff.y, -limit.y);
+						r.position.x += diff.x;
+						r.size.x -= diff.x;
+						r.size.y += diff.y;
+
+					} break;
+					case SUB_WINDOW_RESIZE_BOTTOM: {
+						diff.y = MAX(diff.y, -limit.y);
+						r.size.y += diff.y;
+					} break;
+					case SUB_WINDOW_RESIZE_BOTTOM_RIGHT: {
+						diff.x = MAX(diff.x, -limit.x);
+						diff.y = MAX(diff.y, -limit.y);
+						r.size += diff;
+
+					} break;
+					default: {
+					}
+				}
+
+				gui.subwindow_focused->_rect_changed_callback(r);
+			}
+
+			if (gui.subwindow_focused) { //may have been erased
+				_sub_window_update(gui.subwindow_focused);
+			}
+		}
+
+		return true; //handled
+	}
+	Ref<InputEventMouseButton> mb = p_event;
+	//if the event is a mouse button, we need to check whether another window was clicked
+
+	if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+
+		bool click_on_window = false;
+		for (int i = gui.sub_windows.size() - 1; i >= 0; i--) {
+			SubWindow &sw = gui.sub_windows.write[i];
+
+			//clicked inside window?
+
+			Rect2i r = Rect2i(sw.window->get_position(), sw.window->get_size());
+
+			if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) {
+				//check top bar
+				int title_height = sw.window->get_theme_constant("title_height");
+				Rect2i title_bar = r;
+				title_bar.position.y -= title_height;
+				title_bar.size.y = title_height;
+
+				if (title_bar.has_point(mb->get_position())) {
+
+					click_on_window = true;
+
+					int close_h_ofs = sw.window->get_theme_constant("close_h_ofs");
+					int close_v_ofs = sw.window->get_theme_constant("close_v_ofs");
+					Ref<Texture2D> close_icon = sw.window->get_theme_icon("close");
+
+					Rect2 close_rect;
+					close_rect.position = Vector2(r.position.x + r.size.x - close_v_ofs, r.position.y - close_h_ofs);
+					close_rect.size = close_icon->get_size();
+
+					if (gui.subwindow_focused != sw.window) {
+						//refocus
+						_sub_window_grab_focus(sw.window);
+					}
+
+					if (close_rect.has_point(mb->get_position())) {
+
+						gui.subwindow_drag = SUB_WINDOW_DRAG_CLOSE;
+						gui.subwindow_drag_close_inside = true; //starts inside
+						gui.subwindow_drag_close_rect = close_rect;
+					} else {
+
+						gui.subwindow_drag = SUB_WINDOW_DRAG_MOVE;
+					}
+
+					gui.subwindow_drag_from = mb->get_position();
+					gui.subwindow_drag_pos = sw.window->get_position();
+
+					_sub_window_update(sw.window);
+				} else {
+					gui.subwindow_resize_mode = _sub_window_get_resize_margin(gui.subwindow_focused, mb->get_position());
+					if (gui.subwindow_resize_mode != SUB_WINDOW_RESIZE_DISABLED) {
+						gui.subwindow_resize_from_rect = r;
+						gui.subwindow_drag_from = mb->get_position();
+						gui.subwindow_drag = SUB_WINDOW_DRAG_RESIZE;
+						click_on_window = true;
+					}
+				}
+			}
+			if (!click_on_window && r.has_point(mb->get_position())) {
+				//clicked, see if it needs to fetch focus
+				if (gui.subwindow_focused != sw.window) {
+					//refocus
+					_sub_window_grab_focus(sw.window);
+				}
+
+				click_on_window = true;
+			}
+
+			if (click_on_window) {
+				break;
+			}
+		}
+
+		if (!click_on_window && gui.subwindow_focused) {
+			//no window found and clicked, remove focus
+			_sub_window_grab_focus(nullptr);
+		}
+	}
+
+	if (gui.subwindow_focused) {
+
+		Ref<InputEventMouseMotion> mm = p_event;
+		if (mm.is_valid()) {
+
+			SubWindowResize resize = _sub_window_get_resize_margin(gui.subwindow_focused, mm->get_position());
+			if (resize != SUB_WINDOW_RESIZE_DISABLED) {
+
+				DisplayServer::CursorShape shapes[SUB_WINDOW_RESIZE_MAX] = {
+					DisplayServer::CURSOR_ARROW,
+					DisplayServer::CURSOR_FDIAGSIZE,
+					DisplayServer::CURSOR_VSIZE,
+					DisplayServer::CURSOR_BDIAGSIZE,
+					DisplayServer::CURSOR_HSIZE,
+					DisplayServer::CURSOR_HSIZE,
+					DisplayServer::CURSOR_BDIAGSIZE,
+					DisplayServer::CURSOR_VSIZE,
+					DisplayServer::CURSOR_FDIAGSIZE
+				};
+
+				DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]);
+
+				return true; //reserved for showing the resize cursor
+			}
+		}
+	}
+
+	if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
+		return true; // dragging, don't pass the event
+	}
+
+	if (!gui.subwindow_focused) {
+		return false;
+	}
+
+	Transform2D window_ofs;
+	window_ofs.set_origin(-gui.subwindow_focused->get_position());
+
+	Ref<InputEvent> ev = p_event->xformed_by(window_ofs);
+
+	gui.subwindow_focused->_window_input(ev);
+
+	return true;
+}
+
 void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
 
 	ERR_FAIL_COND(!is_inside_tree());
@@ -2671,6 +2924,11 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
 		ev = p_event;
 	}
 
+	if (is_embedding_subwindows() && _sub_windows_forward_input(p_event)) {
+		set_input_as_handled();
+		return;
+	}
+
 	if (!is_input_handled()) {
 		get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
 	}
@@ -2782,11 +3040,6 @@ Vector2 Viewport::get_camera_rect_size() const {
 	return size;
 }
 
-bool Viewport::gui_has_modal_stack() const {
-
-	return gui.modal_stack.size();
-}
-
 void Viewport::set_disable_input(bool p_disable) {
 	disable_input = p_disable;
 }
@@ -2800,10 +3053,6 @@ Variant Viewport::gui_get_drag_data() const {
 	return gui.drag_data;
 }
 
-Control *Viewport::get_modal_stack_top() const {
-	return gui.modal_stack.size() ? gui.modal_stack.back()->get() : NULL;
-}
-
 String Viewport::get_configuration_warning() const {
 	/*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) {
 
@@ -3039,12 +3288,9 @@ void Viewport::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position);
 	ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse);
 
-	ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack);
 	ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
 	ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);
 
-	ClassDB::bind_method(D_METHOD("get_modal_stack_top"), &Viewport::get_modal_stack_top);
-
 	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);
 
@@ -3157,13 +3403,6 @@ void Viewport::_bind_methods() {
 	BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
 }
 
-void Viewport::_subwindow_visibility_changed() {
-
-	// unfortunately, we don't know the sender, i.e. which subwindow changed;
-	// so we have to check them all.
-	gui.subwindow_visibility_dirty = true;
-}
-
 Viewport::Viewport() {
 
 	world_2d = Ref<World2D>(memnew(World2D));
@@ -3227,6 +3466,8 @@ Viewport::Viewport() {
 	gui.roots_order_dirty = false;
 	gui.mouse_focus = NULL;
 	gui.last_mouse_focus = NULL;
+	gui.subwindow_focused = nullptr;
+	gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
 
 	msaa = MSAA_DISABLED;
 
@@ -3302,6 +3543,16 @@ DisplayServer::WindowID SubViewport::get_window_id() const {
 	return DisplayServer::INVALID_WINDOW_ID;
 }
 
+void SubViewport::_notification(int p_what) {
+
+	if (p_what == NOTIFICATION_ENTER_TREE) {
+		VS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
+	}
+	if (p_what == NOTIFICATION_EXIT_TREE) {
+		VS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
+	}
+}
+
 void SubViewport::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &SubViewport::set_use_arvr);
 	ClassDB::bind_method(D_METHOD("is_using_arvr"), &SubViewport::is_using_arvr);
@@ -3323,6 +3574,7 @@ void SubViewport::_bind_methods() {
 	BIND_ENUM_CONSTANT(UPDATE_DISABLED);
 	BIND_ENUM_CONSTANT(UPDATE_ONCE);
 	BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE);
+	BIND_ENUM_CONSTANT(UPDATE_WHEN_PARENT_VISIBLE);
 	BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
 
 	BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);

+ 56 - 25
scene/main/viewport.h

@@ -151,6 +151,10 @@ public:
 		DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX,
 	};
 
+	enum {
+		SUBWINDOW_CANVAS_LAYER = 1024
+	};
+
 private:
 	friend class ViewportTexture;
 
@@ -183,6 +187,7 @@ private:
 
 	RID viewport;
 	RID current_canvas;
+	RID subwindow_canvas;
 
 	bool audio_listener;
 	RID internal_listener;
@@ -269,6 +274,31 @@ private:
 	Ref<ViewportTexture> default_texture;
 	Set<ViewportTexture *> viewport_textures;
 
+	enum SubWindowDrag {
+		SUB_WINDOW_DRAG_DISABLED,
+		SUB_WINDOW_DRAG_MOVE,
+		SUB_WINDOW_DRAG_CLOSE,
+		SUB_WINDOW_DRAG_RESIZE,
+	};
+
+	enum SubWindowResize {
+		SUB_WINDOW_RESIZE_DISABLED,
+		SUB_WINDOW_RESIZE_TOP_LEFT,
+		SUB_WINDOW_RESIZE_TOP,
+		SUB_WINDOW_RESIZE_TOP_RIGHT,
+		SUB_WINDOW_RESIZE_LEFT,
+		SUB_WINDOW_RESIZE_RIGHT,
+		SUB_WINDOW_RESIZE_BOTTOM_LEFT,
+		SUB_WINDOW_RESIZE_BOTTOM,
+		SUB_WINDOW_RESIZE_BOTTOM_RIGHT,
+		SUB_WINDOW_RESIZE_MAX
+	};
+
+	struct SubWindow {
+		Window *window;
+		RID canvas_item;
+	};
+
 	struct GUI {
 		// info used when this is a window
 
@@ -290,17 +320,24 @@ private:
 		Control *drag_preview;
 		float tooltip_timer;
 		float tooltip_delay;
-		List<Control *> modal_stack;
 		Transform2D focus_inv_xform;
-		bool subwindow_order_dirty;
-		bool subwindow_visibility_dirty;
-		List<Control *> subwindows; // visible subwindows
-		List<Control *> all_known_subwindows;
 		bool roots_order_dirty;
 		List<Control *> roots;
 		int canvas_sort_index; //for sorting items with canvas as root
 		bool dragging;
 		bool embed_subwindows_hint;
+		bool embedding_subwindows;
+
+		Window *subwindow_focused;
+		SubWindowDrag subwindow_drag;
+		Vector2 subwindow_drag_from;
+		Vector2 subwindow_drag_pos;
+		Rect2i subwindow_drag_close_rect;
+		bool subwindow_drag_close_inside;
+		SubWindowResize subwindow_resize_mode;
+		Rect2i subwindow_resize_from_rect;
+
+		Vector<SubWindow> sub_windows;
 
 		GUI();
 	} gui;
@@ -316,10 +353,7 @@ private:
 	void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
 	void _gui_call_notification(Control *p_control, int p_what);
 
-	void _gui_prepare_subwindows();
-	void _gui_sort_subwindows();
 	void _gui_sort_roots();
-	void _gui_sort_modal_stack();
 	Control *_gui_find_control(const Point2 &p_global);
 	Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform);
 
@@ -334,15 +368,8 @@ private:
 	friend class Control;
 
 	List<Control *>::Element *_gui_add_root_control(Control *p_control);
-	List<Control *>::Element *_gui_add_subwindow_control(Control *p_control);
 
-	void _gui_set_subwindow_order_dirty();
-	void _gui_set_root_order_dirty();
-
-	void _gui_remove_modal_control(List<Control *>::Element *MI);
-	void _gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner);
 	void _gui_remove_root_control(List<Control *>::Element *RI);
-	void _gui_remove_subwindow_control(List<Control *>::Element *SI);
 
 	String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL);
 	void _gui_cancel_tooltip();
@@ -354,9 +381,6 @@ private:
 	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);
 
-	bool _gui_is_modal_on_top(const Control *p_control);
-	List<Control *>::Element *_gui_show_modal(Control *p_control);
-
 	void _gui_remove_focus();
 	void _gui_unfocus_control(Control *p_control);
 	bool _gui_control_has_focus(const Control *p_control);
@@ -367,8 +391,6 @@ private:
 
 	Control *_gui_get_focus_owner();
 
-	Vector2 _get_window_offset() const;
-
 	bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check);
 
 	friend class Listener;
@@ -394,8 +416,20 @@ private:
 
 	void _update_canvas_items(Node *p_node);
 
+	void _gui_set_root_order_dirty();
+
 	void _own_world_changed();
 
+	friend class Window;
+
+	void _sub_window_update_order();
+	void _sub_window_register(Window *p_window);
+	void _sub_window_update(Window *p_window);
+	void _sub_window_grab_focus(Window *p_window);
+	void _sub_window_remove(Window *p_window);
+	bool _sub_windows_forward_input(const Ref<InputEvent> &p_event);
+	SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point);
+
 protected:
 	void _set_size(const Size2i &p_size, const Size2i &p_size_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated);
 
@@ -485,10 +519,7 @@ public:
 	void set_physics_object_picking(bool p_enable);
 	bool get_physics_object_picking();
 
-	bool gui_has_modal_stack() const;
-
 	Variant gui_get_drag_data() const;
-	Control *get_modal_stack_top() const;
 
 	void gui_reset_canvas_sort_index();
 	int gui_get_canvas_sort_index();
@@ -503,8 +534,6 @@ public:
 	void set_snap_controls_to_pixels(bool p_enable);
 	bool is_snap_controls_to_pixels_enabled() const;
 
-	void _subwindow_visibility_changed();
-
 	void set_input_as_handled();
 	bool is_input_handled() const;
 
@@ -546,6 +575,7 @@ public:
 		UPDATE_DISABLED,
 		UPDATE_ONCE, //then goes to disabled
 		UPDATE_WHEN_VISIBLE, // default
+		UPDATE_WHEN_PARENT_VISIBLE,
 		UPDATE_ALWAYS
 	};
 
@@ -557,6 +587,7 @@ private:
 protected:
 	static void _bind_methods();
 	virtual DisplayServer::WindowID get_window_id() const;
+	void _notification(int p_what);
 
 public:
 	void set_size(const Size2i &p_size);

+ 239 - 89
scene/main/window.cpp

@@ -37,9 +37,14 @@
 #include "scene/scene_string_names.h"
 void Window::set_title(const String &p_title) {
 	title = p_title;
-	if (window_id == DisplayServer::INVALID_WINDOW_ID)
-		return;
-	DisplayServer::get_singleton()->window_set_title(p_title, window_id);
+
+	if (embedder) {
+		embedder->_sub_window_update(this);
+
+	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+		DisplayServer::get_singleton()->window_set_title(p_title, window_id);
+	}
 }
 String Window::get_title() const {
 	return title;
@@ -61,28 +66,25 @@ int Window::get_current_screen() const {
 void Window::set_position(const Point2i &p_position) {
 
 	position = p_position;
-	if (window_id == DisplayServer::INVALID_WINDOW_ID)
-		return;
-	DisplayServer::get_singleton()->window_set_position(p_position, window_id);
+
+	if (embedder) {
+		embedder->_sub_window_update(this);
+
+	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+		DisplayServer::get_singleton()->window_set_position(p_position, window_id);
+	}
 }
 Point2i Window::get_position() const {
-	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-		position = DisplayServer::get_singleton()->window_get_position(window_id);
-	}
 	return position;
 }
 
 void Window::set_size(const Size2i &p_size) {
 	size = p_size;
-	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-		DisplayServer::get_singleton()->window_set_size(p_size, window_id);
-	}
-	_update_size();
+	_update_window_size();
 }
 Size2i Window::get_size() const {
-	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-		size = DisplayServer::get_singleton()->window_get_size(window_id);
-	}
+
 	return size;
 }
 
@@ -96,22 +98,19 @@ Size2i Window::get_real_size() const {
 
 void Window::set_max_size(const Size2i &p_max_size) {
 	max_size = p_max_size;
-	if (window_id == DisplayServer::INVALID_WINDOW_ID)
-		return;
-	DisplayServer::get_singleton()->window_set_max_size(p_max_size, window_id);
+	DisplayServer::get_singleton()->window_set_min_size(max_size, window_id);
+	_update_window_size();
 }
 Size2i Window::get_max_size() const {
-	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-		max_size = DisplayServer::get_singleton()->window_get_max_size(window_id);
-	}
-	return max_size;
+
+	return min_size;
 }
 
 void Window::set_min_size(const Size2i &p_min_size) {
+
 	min_size = p_min_size;
-	if (window_id == DisplayServer::INVALID_WINDOW_ID)
-		return;
-	DisplayServer::get_singleton()->window_set_min_size(p_min_size, window_id);
+	DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
+	_update_window_size();
 }
 Size2i Window::get_min_size() const {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
@@ -123,9 +122,14 @@ Size2i Window::get_min_size() const {
 void Window::set_mode(Mode p_mode) {
 
 	mode = p_mode;
-	if (window_id == DisplayServer::INVALID_WINDOW_ID)
-		return;
-	DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id);
+
+	if (embedder) {
+		embedder->_sub_window_update(this);
+
+	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+		DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id);
+	}
 }
 
 Window::Mode Window::get_mode() const {
@@ -139,9 +143,14 @@ Window::Mode Window::get_mode() const {
 void Window::set_flag(Flags p_flag, bool p_enabled) {
 	ERR_FAIL_INDEX(p_flag, FLAG_MAX);
 	flags[p_flag] = p_enabled;
-	if (window_id == DisplayServer::INVALID_WINDOW_ID)
-		return;
-	DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
+
+	if (embedder) {
+		embedder->_sub_window_update(this);
+
+	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+		DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
+	}
 }
 
 bool Window::get_flag(Flags p_flag) const {
@@ -165,7 +174,11 @@ void Window::request_attention() {
 	}
 }
 void Window::move_to_foreground() {
-	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+	if (embedder) {
+		embedder->_sub_window_grab_focus(this);
+
+	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		DisplayServer::get_singleton()->window_move_to_foreground(window_id);
 	}
 }
@@ -178,7 +191,7 @@ bool Window::can_draw() const {
 		return DisplayServer::get_singleton()->window_can_draw(window_id);
 	}
 
-	return true;
+	return visible;
 }
 
 void Window::set_ime_active(bool p_active) {
@@ -194,11 +207,8 @@ void Window::set_ime_position(const Point2i &p_pos) {
 
 bool Window::is_embedded() const {
 	ERR_FAIL_COND_V(!is_inside_tree(), false);
-	if (get_parent_viewport()) {
-		return get_parent_viewport()->is_embedding_subwindows();
-	} else {
-		return false;
-	}
+	Viewport *parent_vp = get_parent_viewport();
+	return parent_vp && parent_vp->is_embedding_subwindows();
 }
 
 void Window::_make_window() {
@@ -210,6 +220,7 @@ void Window::_make_window() {
 			f |= (1 << i);
 		}
 	}
+
 	window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size));
 	ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
 	DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
@@ -217,7 +228,7 @@ void Window::_make_window() {
 	DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
 	DisplayServer::get_singleton()->window_set_title(title, window_id);
 
-	_update_size();
+	_update_window_size();
 
 	if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) {
 		DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id);
@@ -228,6 +239,8 @@ void Window::_make_window() {
 			DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, transient_parent->window_id);
 		}
 	}
+
+	VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_VISIBLE);
 }
 void Window::_update_from_window() {
 
@@ -236,10 +249,6 @@ void Window::_update_from_window() {
 	for (int i = 0; i < FLAG_MAX; i++) {
 		flags[i] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(i), window_id);
 	}
-	position = DisplayServer::get_singleton()->window_get_position(window_id);
-	size = DisplayServer::get_singleton()->window_get_size(window_id);
-	max_size = DisplayServer::get_singleton()->window_get_max_size(window_id);
-	min_size = DisplayServer::get_singleton()->window_get_min_size(window_id);
 }
 
 void Window::_clear_window() {
@@ -256,16 +265,26 @@ void Window::_clear_window() {
 	}
 
 	_update_from_window();
-	print_line("deleting window bye");
+
 	DisplayServer::get_singleton()->delete_sub_window(window_id);
 	window_id = DisplayServer::INVALID_WINDOW_ID;
-	_update_size();
+	_update_viewport_size();
+
+	VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED);
 }
 
-void Window::_resize_callback(const Size2i &p_callback) {
+void Window::_rect_changed_callback(const Rect2i &p_callback) {
 
-	size = p_callback;
-	_update_size();
+	//we must always accept this as the truth
+	if (size == p_callback.size && position == p_callback.position) {
+		return;
+	}
+	position = p_callback.position;
+
+	if (size != p_callback.size) {
+		size = p_callback.size;
+		_update_viewport_size();
+	}
 }
 
 void Window::_propagate_window_notification(Node *p_node, int p_notification) {
@@ -335,11 +354,15 @@ void Window::set_visible(bool p_visible) {
 		return;
 	}
 
+	if (updating_child_controls) {
+		_update_child_controls();
+	}
+
 	ERR_FAIL_COND_MSG(get_parent() == nullptr, "Can't change visibility of main window.");
 
-	bool subwindow = get_parent() && get_parent()->get_viewport()->is_embedding_subwindows();
+	Viewport *embedder_vp = _get_embedder();
 
-	if (!subwindow) {
+	if (!embedder_vp) {
 		if (!p_visible && window_id != DisplayServer::INVALID_WINDOW_ID) {
 			_clear_window();
 		}
@@ -348,7 +371,16 @@ void Window::set_visible(bool p_visible) {
 			_update_window_callbacks();
 		}
 	} else {
-		_update_size();
+		if (visible) {
+			embedder = embedder_vp;
+			embedder->_sub_window_register(this);
+			VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
+		} else {
+			embedder->_sub_window_remove(this);
+			embedder = nullptr;
+			VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED);
+		}
+		_update_window_size();
 	}
 
 	if (!visible) {
@@ -356,6 +388,8 @@ void Window::set_visible(bool p_visible) {
 	}
 	notification(NOTIFICATION_VISIBILITY_CHANGED);
 	emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+
+	VS::get_singleton()->viewport_set_active(get_viewport_rid(), visible);
 }
 
 void Window::_clear_transient() {
@@ -458,7 +492,38 @@ bool Window::is_visible() const {
 	return visible;
 }
 
-void Window::_update_size() {
+void Window::_update_window_size() {
+
+	Size2i size_limit;
+	if (wrap_controls) {
+		size_limit = get_contents_minimum_size();
+	}
+
+	size_limit.x = MAX(size_limit.x, min_size.x);
+	size_limit.y = MAX(size_limit.y, min_size.y);
+
+	size.x = MAX(size_limit.x, size.x);
+	size.y = MAX(size_limit.y, size.y);
+
+	if (max_size.x > 0 && max_size.x > min_size.x && max_size.x > size.x) {
+		size.x = max_size.x;
+	}
+
+	if (max_size.y > 0 && max_size.y > min_size.y && max_size.y > size.y) {
+		size.y = max_size.y;
+	}
+
+	if (embedder) {
+		embedder->_sub_window_update(this);
+	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+		DisplayServer::get_singleton()->window_set_size(size, window_id);
+	}
+
+	//update the viewport
+	_update_viewport_size();
+}
+void Window::_update_viewport_size() {
+	//update the viewport part
 
 	Size2i final_size;
 	Size2i final_size_override;
@@ -563,7 +628,7 @@ void Window::_update_size() {
 		stretch_transform.elements[2] = margin * scale;
 	}
 
-	bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || (get_parent() && get_parent()->get_viewport()->is_embedding_subwindows()));
+	bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr);
 
 	_set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform, allocate);
 
@@ -586,28 +651,78 @@ void Window::_update_size() {
 	}
 
 	notification(NOTIFICATION_WM_SIZE_CHANGED);
+
+	if (embedder) {
+		embedder->_sub_window_update(this);
+	}
 }
 
 void Window::_update_window_callbacks() {
-	DisplayServer::get_singleton()->window_set_resize_callback(callable_mp(this, &Window::_resize_callback), window_id);
+	DisplayServer::get_singleton()->window_set_rect_changed_callback(callable_mp(this, &Window::_rect_changed_callback), window_id);
 	DisplayServer::get_singleton()->window_set_window_event_callback(callable_mp(this, &Window::_event_callback), window_id);
 	DisplayServer::get_singleton()->window_set_input_event_callback(callable_mp(this, &Window::_window_input), window_id);
 	DisplayServer::get_singleton()->window_set_input_text_callback(callable_mp(this, &Window::_window_input_text), window_id);
 	DisplayServer::get_singleton()->window_set_drop_files_callback(callable_mp(this, &Window::_window_drop_files), window_id);
 }
+
+Viewport *Window::_get_embedder() const {
+
+	Viewport *vp = get_parent_viewport();
+
+	while (vp) {
+
+		if (vp->is_embedding_subwindows()) {
+			return vp;
+		}
+
+		if (vp->get_parent()) {
+			vp = vp->get_parent()->get_viewport();
+		} else {
+			vp = nullptr;
+		}
+	}
+	return nullptr;
+}
+
 void Window::_notification(int p_what) {
 	if (p_what == NOTIFICATION_ENTER_TREE) {
-		if (is_embedded()) {
+
+		bool embedded = false;
+		{
+
+			embedder = _get_embedder();
+
+			if (embedder) {
+				embedded = true;
+
+				if (!visible) {
+					embedder = nullptr; //not yet since not visible
+				}
+			}
+		}
+
+		if (embedded) {
 			//create as embedded
-			_update_size();
+			if (embedder) {
+				embedder->_sub_window_register(this);
+				VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
+				_update_window_size();
+			}
+
 		} else {
 			if (get_parent() == nullptr) {
 				//it's the root window!
 				visible = true; //always visible
 				window_id = DisplayServer::MAIN_WINDOW_ID;
 				_update_from_window();
-				_update_size();
+				//since this window already exists (created on start), we must update pos and size from it
+				{
+					position = DisplayServer::get_singleton()->window_get_position(window_id);
+					size = DisplayServer::get_singleton()->window_get_size(window_id);
+				}
+				_update_viewport_size(); //then feed back to the viewport
 				_update_window_callbacks();
+				VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_WHEN_VISIBLE);
 			} else {
 				//create
 				if (visible) {
@@ -623,6 +738,7 @@ void Window::_notification(int p_what) {
 		if (visible) {
 			notification(NOTIFICATION_VISIBILITY_CHANGED);
 			emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+			VS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
 		}
 	}
 
@@ -643,13 +759,22 @@ void Window::_notification(int p_what) {
 
 			if (window_id == DisplayServer::MAIN_WINDOW_ID) {
 
+				VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED);
 				_update_window_callbacks();
 			} else {
 				_clear_window();
 			}
 		} else {
-			_update_size(); //called by clear and make, which does not happen here
+
+			if (embedder) {
+				embedder->_sub_window_remove(this);
+				embedder = nullptr;
+				VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED);
+			}
+			_update_viewport_size(); //called by clear and make, which does not happen here
 		}
+
+		VS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
 	}
 }
 
@@ -657,7 +782,7 @@ void Window::set_content_scale_size(const Size2i &p_size) {
 	ERR_FAIL_COND(p_size.x < 0);
 	ERR_FAIL_COND(p_size.y < 0);
 	content_scale_size = p_size;
-	_update_size();
+	_update_viewport_size();
 }
 
 Size2i Window::get_content_scale_size() const {
@@ -666,7 +791,7 @@ Size2i Window::get_content_scale_size() const {
 
 void Window::set_content_scale_mode(ContentScaleMode p_mode) {
 	content_scale_mode = p_mode;
-	_update_size();
+	_update_viewport_size();
 }
 Window::ContentScaleMode Window::get_content_scale_mode() const {
 	return content_scale_mode;
@@ -674,7 +799,7 @@ Window::ContentScaleMode Window::get_content_scale_mode() const {
 
 void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) {
 	content_scale_aspect = p_aspect;
-	_update_size();
+	_update_viewport_size();
 }
 Window::ContentScaleAspect Window::get_content_scale_aspect() const {
 	return content_scale_aspect;
@@ -685,7 +810,7 @@ void Window::set_use_font_oversampling(bool p_oversampling) {
 		ERR_FAIL_MSG("Only the root window can set and use font oversampling.");
 	}
 	use_font_oversampling = p_oversampling;
-	_update_size();
+	_update_viewport_size();
 }
 bool Window::is_using_font_oversampling() const {
 	return use_font_oversampling;
@@ -724,22 +849,17 @@ Size2 Window::_get_contents_minimum_size() const {
 }
 void Window::_update_child_controls() {
 
-	Size2 max = _get_contents_minimum_size();
+	if (!updating_child_controls) {
+		return;
+	}
 
-	Size2 new_size(MAX(max.x, size.x), MAX(max.y, size.y));
+	_update_window_size();
 
-	if (new_size != size) {
-		set_size(new_size);
-	}
-	set_min_size(max);
 	updating_child_controls = false;
 }
 void Window::child_controls_changed() {
-	if (!is_inside_tree()) {
-		return;
-	}
 
-	if (updating_child_controls) {
+	if (!is_inside_tree() || !visible || updating_child_controls) {
 		return;
 	}
 
@@ -762,7 +882,7 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
 
 	if (exclusive_child != nullptr) {
 		exclusive_child->grab_focus();
-		print_line("drop because of exclusive");
+
 		return; //has an exclusive child, can't get events until child is closed
 	}
 
@@ -901,6 +1021,7 @@ void Window::popup_centered_ratio(float p_ratio) {
 void Window::popup(const Rect2 &p_screen_rect) {
 
 	emit_signal("about_to_popup");
+
 	if (p_screen_rect != Rect2()) {
 		set_position(p_screen_rect.position);
 		set_size(p_screen_rect.size);
@@ -917,7 +1038,9 @@ Size2 Window::get_contents_minimum_size() const {
 }
 
 void Window::grab_focus() {
-	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+	if (embedder) {
+		embedder->_sub_window_grab_focus(this);
+	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		DisplayServer::get_singleton()->window_move_to_foreground(window_id);
 	}
 }
@@ -939,6 +1062,10 @@ void Window::add_child_notify(Node *p_child) {
 	if (child_w && child_w->theme.is_null() && (theme_owner || theme_owner_window)) {
 		Control::_propagate_theme_changed(child_w, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff
 	}
+
+	if (is_inside_tree() && wrap_controls) {
+		child_controls_changed();
+	}
 }
 
 void Window::remove_child_notify(Node *p_child) {
@@ -954,6 +1081,10 @@ void Window::remove_child_notify(Node *p_child) {
 	if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
 		Control::_propagate_theme_changed(child_w, NULL, NULL);
 	}
+
+	if (is_inside_tree() && wrap_controls) {
+		child_controls_changed();
+	}
 }
 
 void Window::set_theme(const Ref<Theme> &p_theme) {
@@ -988,47 +1119,65 @@ Ref<Theme> Window::get_theme() const {
 }
 
 Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_type) const {
-	return Control::get_icons(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::get_icons(theme_owner, theme_owner_window, p_name, type);
 }
 Ref<Shader> Window::get_theme_shader(const StringName &p_name, const StringName &p_type) const {
-	return Control::get_shaders(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::get_shaders(theme_owner, theme_owner_window, p_name, type);
 }
 Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
-	return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, type);
 }
 Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_type) const {
-	return Control::get_fonts(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::get_fonts(theme_owner, theme_owner_window, p_name, type);
 }
 Color Window::get_theme_color(const StringName &p_name, const StringName &p_type) const {
-	return Control::get_colors(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::get_colors(theme_owner, theme_owner_window, p_name, type);
 }
 int Window::get_theme_constant(const StringName &p_name, const StringName &p_type) const {
-	return Control::get_constants(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::get_constants(theme_owner, theme_owner_window, p_name, type);
 }
 
 bool Window::has_theme_icon(const StringName &p_name, const StringName &p_type) const {
-	return Control::has_icons(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::has_icons(theme_owner, theme_owner_window, p_name, type);
 }
 bool Window::has_theme_shader(const StringName &p_name, const StringName &p_type) const {
-	return Control::has_shaders(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::has_shaders(theme_owner, theme_owner_window, p_name, type);
 }
 bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
-	return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, type);
 }
 bool Window::has_theme_font(const StringName &p_name, const StringName &p_type) const {
-	return Control::has_fonts(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::has_fonts(theme_owner, theme_owner_window, p_name, type);
 }
 bool Window::has_theme_color(const StringName &p_name, const StringName &p_type) const {
-	return Control::has_colors(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::has_colors(theme_owner, theme_owner_window, p_name, type);
 }
 bool Window::has_theme_constant(const StringName &p_name, const StringName &p_type) const {
-	return Control::has_constants(theme_owner, theme_owner_window, p_name, p_type);
+	StringName type = p_type ? p_type : get_class_name();
+	return Control::has_constants(theme_owner, theme_owner_window, p_name, type);
 }
 
-Rect2i Window::get_screen_rect() const {
+Rect2i Window::get_parent_rect() const {
+	ERR_FAIL_COND_V(!is_inside_tree(), Rect2i());
 	if (is_embedded()) {
 		//viewport
-		return Rect2i();
+		Node *n = get_parent();
+		ERR_FAIL_COND_V(!n, Rect2i());
+		Viewport *p = n->get_viewport();
+		ERR_FAIL_COND_V(!p, Rect2i());
+
+		return p->get_visible_rect();
 	} else {
 		int x = get_position().x;
 		int closest_dist = 0x7FFFFFFF;
@@ -1188,6 +1337,7 @@ Window::Window() {
 	}
 	content_scale_mode = CONTENT_SCALE_MODE_DISABLED;
 	content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE;
+	VS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), VS::VIEWPORT_UPDATE_DISABLED);
 }
 Window::~Window() {
 }

+ 15 - 10
scene/main/window.h

@@ -103,20 +103,13 @@ private:
 	void _clear_window();
 	void _update_from_window();
 
-	void _resize_callback(const Size2i &p_callback);
-	void _event_callback(DisplayServer::WindowEvent p_event);
-
-	void _update_size();
+	void _update_viewport_size();
+	void _update_window_size();
 
 	void _propagate_window_notification(Node *p_node, int p_notification);
 
 	virtual DisplayServer::WindowID get_window_id() const;
 
-	void _window_input(const Ref<InputEvent> &p_ev);
-	void _window_input_text(const String &p_text);
-	void _window_drop_files(const Vector<String> &p_files);
-
-	void _window_unhandled_input(const Ref<InputEvent> &p_ev);
 	void _update_window_callbacks();
 
 	void _clear_transient();
@@ -130,6 +123,18 @@ private:
 	Control *theme_owner = nullptr;
 	Window *theme_owner_window = nullptr;
 
+	Viewport *_get_embedder() const;
+
+	Viewport *embedder = nullptr;
+
+	friend class Viewport; //friend back, can call the methods below
+
+	void _window_input(const Ref<InputEvent> &p_ev);
+	void _window_input_text(const String &p_text);
+	void _window_drop_files(const Vector<String> &p_files);
+	void _rect_changed_callback(const Rect2i &p_callback);
+	void _event_callback(DisplayServer::WindowEvent p_event);
+
 protected:
 	virtual void _post_popup() {}
 	virtual Size2 _get_contents_minimum_size() const;
@@ -243,7 +248,7 @@ public:
 	bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
 	bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
 
-	Rect2i get_screen_rect() const;
+	Rect2i get_parent_rect() const;
 
 	Window();
 	~Window();

+ 13 - 12
scene/resources/default_theme/default_theme.cpp

@@ -524,18 +524,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 
 	// WindowDialog
 
-	theme->set_stylebox("panel", "AcceptDialog", default_style);
-	theme->set_stylebox("window_panel", "AcceptDialog", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6));
-	theme->set_constant("scaleborder_size", "AcceptDialog", 4 * scale);
-
-	theme->set_font("title_font", "AcceptDialog", large_font);
-	theme->set_color("title_color", "AcceptDialog", Color(0, 0, 0));
-	theme->set_constant("title_height", "AcceptDialog", 20 * scale);
-
-	theme->set_icon("close", "AcceptDialog", make_icon(close_png));
-	theme->set_icon("close_highlight", "AcceptDialog", make_icon(close_hl_png));
-	theme->set_constant("close_h_ofs", "AcceptDialog", 18 * scale);
-	theme->set_constant("close_v_ofs", "AcceptDialog", 18 * scale);
+	theme->set_stylebox("panel", "Window", default_style);
+	theme->set_stylebox("window_panel", "Window", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6));
+	theme->set_constant("scaleborder_size", "Window", 4 * scale);
+
+	theme->set_font("title_font", "Window", large_font);
+	theme->set_color("title_color", "Window", Color(0, 0, 0));
+	theme->set_constant("title_height", "Window", 20 * scale);
+	theme->set_constant("resize_margin", "Window", 4 * scale);
+
+	theme->set_icon("close", "Window", make_icon(close_png));
+	theme->set_icon("close_highlight", "Window", make_icon(close_hl_png));
+	theme->set_constant("close_h_ofs", "Window", 18 * scale);
+	theme->set_constant("close_v_ofs", "Window", 18 * scale);
 
 	// File Dialog
 

+ 1 - 1
servers/display_server.cpp

@@ -276,7 +276,7 @@ void DisplayServer::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("window_get_size", "window_id"), &DisplayServer::window_get_size, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_size", "size", "window_id"), &DisplayServer::window_set_size, DEFVAL(MAIN_WINDOW_ID));
-	ClassDB::bind_method(D_METHOD("window_set_resize_callback", "callback", "window_id"), &DisplayServer::window_set_resize_callback, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_set_rect_changed_callback", "callback", "window_id"), &DisplayServer::window_set_rect_changed_callback, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_window_event_callback", "callback", "window_id"), &DisplayServer::window_set_window_event_callback, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_input_event_callback", "callback", "window_id"), &DisplayServer::window_set_input_event_callback, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_input_text_callback", "callback", "window_id"), &DisplayServer::window_set_input_text_callback, DEFVAL(MAIN_WINDOW_ID));

+ 1 - 1
servers/display_server.h

@@ -182,7 +182,7 @@ public:
 	virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i & = Rect2i());
 	virtual void delete_sub_window(WindowID p_id);
 
-	virtual void window_set_resize_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
+	virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
 
 	enum WindowEvent {
 		WINDOW_EVENT_MOUSE_ENTER,

+ 33 - 4
servers/visual/visual_server_viewport.cpp

@@ -316,7 +316,10 @@ void VisualServerViewport::draw_viewports() {
 	//draw viewports
 	RENDER_TIMESTAMP(">Render Viewports");
 
-	for (int i = 0; i < active_viewports.size(); i++) {
+	//determine what is visible
+	draw_viewports_pass++;
+
+	for (int i = active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
 
 		Viewport *vp = active_viewports[i];
 
@@ -328,11 +331,37 @@ void VisualServerViewport::draw_viewports() {
 		}
 		//ERR_CONTINUE(!vp->render_target.is_valid());
 
-		bool visible = vp->viewport_to_screen_rect != Rect2() || vp->update_mode == VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == VS::VIEWPORT_UPDATE_ONCE || (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_VISIBLE && VSG::storage->render_target_was_used(vp->render_target));
+		bool visible = vp->viewport_to_screen_rect != Rect2();
+
+		if (vp->update_mode == VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == VS::VIEWPORT_UPDATE_ONCE) {
+			visible = true;
+		}
+
+		if (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_VISIBLE && VSG::storage->render_target_was_used(vp->render_target)) {
+			visible = true;
+		}
+
+		if (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) {
+			Viewport *parent = viewport_owner.getornull(vp->parent);
+			if (parent && parent->last_pass == draw_viewports_pass) {
+				visible = true;
+			}
+		}
+
 		visible = visible && vp->size.x > 1 && vp->size.y > 1;
 
-		if (!visible)
-			continue;
+		if (visible) {
+			vp->last_pass = draw_viewports_pass;
+		}
+	}
+
+	for (int i = 0; i < active_viewports.size(); i++) {
+
+		Viewport *vp = active_viewports[i];
+
+		if (vp->last_pass != draw_viewports_pass) {
+			continue; //should not draw
+		}
 
 		RENDER_TIMESTAMP(">Rendering Viewport " + itos(i));
 

+ 6 - 2
servers/visual/visual_server_viewport.h

@@ -73,6 +73,8 @@ public:
 		RID shadow_atlas;
 		int shadow_atlas_size;
 
+		uint64_t last_pass = 0;
+
 		int render_info[VS::VIEWPORT_RENDER_INFO_MAX];
 		VS::ViewportDebugDraw debug_draw;
 
@@ -129,6 +131,8 @@ public:
 		}
 	};
 
+	uint64_t draw_viewports_pass = 0;
+
 	mutable RID_PtrOwner<Viewport> viewport_owner;
 
 	struct ViewportSort {
@@ -139,9 +143,9 @@ public:
 
 			if (left_to_screen == right_to_screen) {
 
-				return p_left->parent == p_right->self;
+				return p_right->parent == p_left->self;
 			}
-			return right_to_screen;
+			return (right_to_screen ? 0 : 1) < (left_to_screen ? 0 : 1);
 		}
 	};
 

+ 1 - 0
servers/visual_server.cpp

@@ -2060,6 +2060,7 @@ void VisualServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED);
 	BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE);
 	BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE);
+	BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
 	BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ALWAYS);
 
 	BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ALWAYS);

+ 1 - 0
servers/visual_server.h

@@ -592,6 +592,7 @@ public:
 		VIEWPORT_UPDATE_DISABLED,
 		VIEWPORT_UPDATE_ONCE, //then goes to disabled, must be manually updated
 		VIEWPORT_UPDATE_WHEN_VISIBLE, // default
+		VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE,
 		VIEWPORT_UPDATE_ALWAYS
 	};