diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index e4dab85038e..6633a40e1a4 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -698,6 +698,9 @@ The preferred monitor to display the project manager. + + If [code]true[/code], the editor window will remember its size, position, and which screen it was displayed on across restarts. + If [code]false[/code], the editor will save all scenes when confirming the [b]Save[/b] action when quitting the editor or quitting to the project list. If [code]true[/code], the editor will ask to save each scene individually. diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index cb647ffc35d..9ca4032dc91 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -672,6 +672,8 @@ void EditorNode::_notification(int p_what) { DisplayServer::get_singleton()->set_system_theme_change_callback(callable_mp(this, &EditorNode::_update_theme).bind(false)); + get_viewport()->connect("size_changed", callable_mp(this, &EditorNode::_viewport_resized)); + /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } break; @@ -700,6 +702,7 @@ void EditorNode::_notification(int p_what) { FileAccess::set_file_close_fail_notify_callback(nullptr); log->deinit(); // Do not get messages anymore. editor_data.clear_edited_scenes(); + get_viewport()->disconnect("size_changed", callable_mp(this, &EditorNode::_viewport_resized)); } break; case NOTIFICATION_READY: { @@ -1197,6 +1200,13 @@ void EditorNode::_reload_project_settings() { void EditorNode::_vp_resized() { } +void EditorNode::_viewport_resized() { + Window *w = get_window(); + if (w) { + was_window_windowed_last = w->get_mode() == Window::MODE_WINDOWED; + } +} + void EditorNode::_titlebar_resized() { DisplayServer::get_singleton()->window_set_window_buttons_offset(Vector2i(title_bar->get_global_position().y + title_bar->get_size().y / 2, title_bar->get_global_position().y + title_bar->get_size().y / 2), DisplayServer::MAIN_WINDOW_ID); const Vector3i &margin = DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID); @@ -5139,6 +5149,7 @@ void EditorNode::_save_editor_layout() { editor_dock_manager->save_docks_to_config(config, "docks"); _save_open_scenes_to_config(config); _save_central_editor_layout_to_config(config); + _save_window_settings_to_config(config, "EditorWindow"); editor_data.get_plugin_window_layout(config); config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); @@ -5248,6 +5259,38 @@ void EditorNode::_load_central_editor_layout_from_config(Ref p_confi } } +void EditorNode::_save_window_settings_to_config(Ref p_layout, const String &p_section) { + Window *w = get_window(); + if (w) { + p_layout->set_value(p_section, "screen", w->get_current_screen()); + + Window::Mode mode = w->get_mode(); + switch (mode) { + case Window::MODE_WINDOWED: + p_layout->set_value(p_section, "mode", "windowed"); + p_layout->set_value(p_section, "size", w->get_size()); + break; + case Window::MODE_FULLSCREEN: + case Window::MODE_EXCLUSIVE_FULLSCREEN: + p_layout->set_value(p_section, "mode", "fullscreen"); + break; + case Window::MODE_MINIMIZED: + if (was_window_windowed_last) { + p_layout->set_value(p_section, "mode", "windowed"); + p_layout->set_value(p_section, "size", w->get_size()); + } else { + p_layout->set_value(p_section, "mode", "maximized"); + } + break; + default: + p_layout->set_value(p_section, "mode", "maximized"); + break; + } + + p_layout->set_value(p_section, "position", w->get_position()); + } +} + void EditorNode::_load_open_scenes_from_config(Ref p_layout) { if (!bool(EDITOR_GET("interface/scene_tabs/restore_scenes_on_load"))) { return; diff --git a/editor/editor_node.h b/editor/editor_node.h index 4d55eaf1b2a..8f23b206996 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -490,6 +490,8 @@ private: SurfaceUpgradeDialog *surface_upgrade_dialog = nullptr; bool run_surface_upgrade_tool = false; + bool was_window_windowed_last = false; + static EditorBuildCallback build_callbacks[MAX_BUILD_CALLBACKS]; static EditorPluginInitializeCallback plugin_init_callbacks[MAX_INIT_CALLBACKS]; static int build_callback_count; @@ -571,6 +573,7 @@ private: void _show_messages(); void _vp_resized(); void _titlebar_resized(); + void _viewport_resized(); void _update_undo_redo_allowed(); @@ -641,6 +644,8 @@ private: void _save_central_editor_layout_to_config(Ref p_config_file); void _load_central_editor_layout_from_config(Ref p_config_file); + void _save_window_settings_to_config(Ref p_layout, const String &p_section); + void _save_open_scenes_to_config(Ref p_layout); void _load_open_scenes_from_config(Ref p_layout); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 1cf3a4e0c41..b014f7eff70 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -447,6 +447,7 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { _initial_set("interface/editor/separate_distraction_mode", false); _initial_set("interface/editor/automatically_open_screenshots", true); EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/single_window_mode", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + _initial_set("interface/editor/remember_window_size_and_position", true); _initial_set("interface/editor/mouse_extra_buttons_navigate_history", true); _initial_set("interface/editor/save_each_scene_on_quit", true); // Regression EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/save_on_focus_loss", false, "") diff --git a/main/main.cpp b/main/main.cpp index e1d53e7f1be..3ae63c48211 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -197,6 +197,7 @@ static bool found_project = false; static bool auto_build_solutions = false; static String debug_server_uri; static bool wait_for_import = false; +static bool restore_editor_window_layout = true; #ifndef DISABLE_DEPRECATED static int converter_max_kb_file = 4 * 1024; // 4MB static int converter_max_line_length = 100000; @@ -2593,6 +2594,7 @@ Error Main::setup2(bool p_show_boot_logo) { bool prefer_wayland_found = false; bool prefer_wayland = false; + bool remember_window_size_and_position_found = false; if (editor) { screen_property = "interface/editor/editor_screen"; @@ -2608,7 +2610,7 @@ Error Main::setup2(bool p_show_boot_logo) { prefer_wayland_found = true; } - while (!screen_found || !prefer_wayland_found) { + while (!screen_found || !prefer_wayland_found || !remember_window_size_and_position_found) { assign = Variant(); next_tag.fields.clear(); next_tag.name = String(); @@ -2628,6 +2630,11 @@ Error Main::setup2(bool p_show_boot_logo) { prefer_wayland = value; prefer_wayland_found = true; } + + if (!remember_window_size_and_position_found && assign == "interface/editor/remember_window_size_and_position") { + restore_editor_window_layout = value; + remember_window_size_and_position_found = true; + } } } @@ -2648,6 +2655,34 @@ Error Main::setup2(bool p_show_boot_logo) { } } + bool has_command_line_window_override = init_use_custom_pos || init_use_custom_screen || init_windowed; + if (editor && !has_command_line_window_override && restore_editor_window_layout) { + Ref config; + config.instantiate(); + // Load and amend existing config if it exists. + Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); + if (err == OK) { + init_screen = config->get_value("EditorWindow", "screen", init_screen); + String mode = config->get_value("EditorWindow", "mode", "maximized"); + window_size = config->get_value("EditorWindow", "size", window_size); + if (mode == "windowed") { + window_mode = DisplayServer::WINDOW_MODE_WINDOWED; + init_windowed = true; + } else if (mode == "fullscreen") { + window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN; + init_fullscreen = true; + } else { + window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED; + init_maximized = true; + } + + if (init_windowed) { + init_use_custom_pos = true; + init_custom_pos = config->get_value("EditorWindow", "position", Vector2i(0, 0)); + } + } + } + OS::get_singleton()->benchmark_end_measure("Startup", "Initialize Early Settings"); } #endif @@ -2768,6 +2803,30 @@ Error Main::setup2(bool p_show_boot_logo) { OS::get_singleton()->benchmark_end_measure("Servers", "Display"); } +#ifdef TOOLS_ENABLED + // If the editor is running in windowed mode, ensure the window rect fits + // the screen in case screen count or position has changed. + if (editor && init_windowed) { + // We still need to check we are actually in windowed mode, because + // certain platform might only support one fullscreen window. + if (DisplayServer::get_singleton()->window_get_mode() == DisplayServer::WINDOW_MODE_WINDOWED) { + Vector2i current_size = DisplayServer::get_singleton()->window_get_size(); + Vector2i current_pos = DisplayServer::get_singleton()->window_get_position(); + int screen = DisplayServer::get_singleton()->window_get_current_screen(); + Rect2i screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen); + + Vector2i adjusted_end = screen_rect.get_end().min(current_pos + current_size); + Vector2i adjusted_pos = screen_rect.get_position().max(adjusted_end - current_size); + Vector2i adjusted_size = DisplayServer::get_singleton()->window_get_min_size().max(adjusted_end - adjusted_pos); + + if (current_pos != adjusted_end || current_size != adjusted_size) { + DisplayServer::get_singleton()->window_set_position(adjusted_pos); + DisplayServer::get_singleton()->window_set_size(adjusted_size); + } + } + } +#endif + if (GLOBAL_GET("debug/settings/stdout/print_fps") || print_fps) { // Print requested V-Sync mode at startup to diagnose the printed FPS not going above the monitor refresh rate. switch (window_vsync_mode) { @@ -3823,6 +3882,8 @@ int Main::start() { if (editor_embed_subwindows) { sml->get_root()->set_embedding_subwindows(true); } + restore_editor_window_layout = EditorSettings::get_singleton()->get_setting( + "interface/editor/remember_window_size_and_position"); } #endif