diff options
31 files changed, 498 insertions, 170 deletions
diff --git a/core/os/os.h b/core/os/os.h index e6ce527720..553ae4cf76 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -75,6 +75,7 @@ class OS { int _display_driver_id = -1; String _current_rendering_driver_name; String _current_rendering_method; + bool _is_gles_over_gl = false; RemoteFilesystemClient default_rfs; @@ -130,9 +131,11 @@ public: void set_current_rendering_driver_name(const String &p_driver_name) { _current_rendering_driver_name = p_driver_name; } void set_current_rendering_method(const String &p_name) { _current_rendering_method = p_name; } + void set_gles_over_gl(bool p_enabled) { _is_gles_over_gl = p_enabled; } String get_current_rendering_driver_name() const { return _current_rendering_driver_name; } String get_current_rendering_method() const { return _current_rendering_method; } + bool get_gles_over_gl() const { return _is_gles_over_gl; } int get_display_driver_id() const { return _display_driver_id; } diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp index 28077fc8c5..0294dbfbbc 100644 --- a/core/string/string_name.cpp +++ b/core/string/string_name.cpp @@ -39,6 +39,30 @@ StaticCString StaticCString::create(const char *p_ptr) { return scs; } +bool StringName::_Data::operator==(const String &p_name) const { + if (cname) { + return p_name == cname; + } else { + return name == p_name; + } +} + +bool StringName::_Data::operator!=(const String &p_name) const { + return !operator==(p_name); +} + +bool StringName::_Data::operator==(const char *p_name) const { + if (cname) { + return strcmp(cname, p_name) == 0; + } else { + return name == p_name; + } +} + +bool StringName::_Data::operator!=(const char *p_name) const { + return !operator==(p_name); +} + StringName _scs_create(const char *p_chr, bool p_static) { return (p_chr[0] ? StringName(StaticCString::create(p_chr), p_static) : StringName()); } @@ -139,19 +163,19 @@ void StringName::unref() { } bool StringName::operator==(const String &p_name) const { - if (!_data) { - return (p_name.length() == 0); + if (_data) { + return _data->operator==(p_name); } - return (_data->get_name() == p_name); + return p_name.is_empty(); } bool StringName::operator==(const char *p_name) const { - if (!_data) { - return (p_name[0] == 0); + if (_data) { + return _data->operator==(p_name); } - return (_data->get_name() == p_name); + return p_name[0] == 0; } bool StringName::operator!=(const String &p_name) const { @@ -168,9 +192,47 @@ bool StringName::operator!=(const StringName &p_name) const { return _data != p_name._data; } -void StringName::operator=(const StringName &p_name) { +char32_t StringName::operator[](int p_index) const { + if (_data) { + if (_data->cname) { + CRASH_BAD_INDEX(p_index, static_cast<long>(strlen(_data->cname))); + return _data->cname[p_index]; + } else { + return _data->name[p_index]; + } + } + + CRASH_BAD_INDEX(p_index, 0); + return 0; +} + +int StringName::length() const { + if (_data) { + if (_data->cname) { + return strlen(_data->cname); + } else { + return _data->name.length(); + } + } + + return 0; +} + +bool StringName::is_empty() const { + if (_data) { + if (_data->cname) { + return _data->cname[0] == 0; + } else { + return _data->name.is_empty(); + } + } + + return true; +} + +StringName &StringName::operator=(const StringName &p_name) { if (this == &p_name) { - return; + return *this; } unref(); @@ -178,6 +240,8 @@ void StringName::operator=(const StringName &p_name) { if (p_name._data && p_name._data->refcount.ref()) { _data = p_name._data; } + + return *this; } StringName::StringName(const StringName &p_name) { @@ -216,7 +280,7 @@ StringName::StringName(const char *p_name, bool p_static) { while (_data) { // compare hash first - if (_data->hash == hash && _data->get_name() == p_name) { + if (_data->hash == hash && _data->operator==(p_name)) { break; } _data = _data->next; @@ -275,7 +339,7 @@ StringName::StringName(const StaticCString &p_static_string, bool p_static) { while (_data) { // compare hash first - if (_data->hash == hash && _data->get_name() == p_static_string.ptr) { + if (_data->hash == hash && _data->operator==(p_static_string.ptr)) { break; } _data = _data->next; @@ -333,7 +397,7 @@ StringName::StringName(const String &p_name, bool p_static) { _data = _table[idx]; while (_data) { - if (_data->hash == hash && _data->get_name() == p_name) { + if (_data->hash == hash && _data->operator==(p_name)) { break; } _data = _data->next; @@ -392,7 +456,7 @@ StringName StringName::search(const char *p_name) { while (_data) { // compare hash first - if (_data->hash == hash && _data->get_name() == p_name) { + if (_data->hash == hash && _data->operator==(p_name)) { break; } _data = _data->next; @@ -429,7 +493,7 @@ StringName StringName::search(const char32_t *p_name) { while (_data) { // compare hash first - if (_data->hash == hash && _data->get_name() == p_name) { + if (_data->hash == hash && _data->operator==(p_name)) { break; } _data = _data->next; @@ -455,7 +519,7 @@ StringName StringName::search(const String &p_name) { while (_data) { // compare hash first - if (_data->hash == hash && p_name == _data->get_name()) { + if (_data->hash == hash && _data->operator==(p_name)) { break; } _data = _data->next; @@ -474,15 +538,15 @@ StringName StringName::search(const String &p_name) { } bool operator==(const String &p_name, const StringName &p_string_name) { - return p_name == p_string_name.operator String(); + return p_string_name.operator==(p_name); } bool operator!=(const String &p_name, const StringName &p_string_name) { - return p_name != p_string_name.operator String(); + return p_string_name.operator!=(p_name); } bool operator==(const char *p_name, const StringName &p_string_name) { - return p_name == p_string_name.operator String(); + return p_string_name.operator==(p_name); } bool operator!=(const char *p_name, const StringName &p_string_name) { - return p_name != p_string_name.operator String(); + return p_string_name.operator!=(p_name); } diff --git a/core/string/string_name.h b/core/string/string_name.h index 0eb98cf64b..288e2c7520 100644 --- a/core/string/string_name.h +++ b/core/string/string_name.h @@ -60,6 +60,11 @@ class StringName { uint32_t debug_references = 0; #endif String get_name() const { return cname ? String(cname) : name; } + bool operator==(const String &p_name) const; + bool operator!=(const String &p_name) const; + bool operator==(const char *p_name) const; + bool operator!=(const char *p_name) const; + int idx = 0; uint32_t hash = 0; _Data *prev = nullptr; @@ -99,6 +104,10 @@ public: bool operator!=(const String &p_name) const; bool operator!=(const char *p_name) const; + char32_t operator[](int p_index) const; + int length() const; + bool is_empty() const; + _FORCE_INLINE_ bool is_node_unique_name() const { if (!_data) { return false; @@ -175,7 +184,7 @@ public: } }; - void operator=(const StringName &p_name); + StringName &operator=(const StringName &p_name); StringName(const char *p_name, bool p_static = false); StringName(const StringName &p_name); StringName(const String &p_name, bool p_static = false); diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index b6565b81f2..d2118f1942 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -194,6 +194,9 @@ The maximum number of script functions that can be displayed per frame in the profiler. If there are more script functions called in a given profiler frame, these functions will be discarded from the profiling results entirely. [b]Note:[/b] This setting is only read when the profiler is first started, so changing it during profiling will have no effect. </member> + <member name="debugger/profiler_target_fps" type="int" setter="" getter=""> + The target frame rate shown in the visual profiler graph, in frames per second. + </member> <member name="debugger/remote_inspect_refresh_interval" type="float" setter="" getter=""> The refresh interval for the remote inspector's properties (in seconds). Lower values are more reactive, but may cause stuttering while the project is running from the editor and the [b]Remote[/b] scene tree is selected in the Scene tree dock. </member> diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 80a4a792bb..92c96519d2 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -113,6 +113,7 @@ public: static void make_current(bool p_gles_over_gl) { gles_over_gl = p_gles_over_gl; + OS::get_singleton()->set_gles_over_gl(gles_over_gl); _create_func = _create_current; low_end = true; } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 3ed8042f3f..8b6d3e3268 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -912,7 +912,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p RS::SkyMode sky_mode = sky->mode; if (sky_mode == RS::SKY_MODE_AUTOMATIC) { - if (shader_data->uses_time || shader_data->uses_position) { + if ((shader_data->uses_time || shader_data->uses_position) && sky->radiance_size == 256) { update_single_frame = true; sky_mode = RS::SKY_MODE_REALTIME; } else if (shader_data->uses_light || shader_data->ubo_size > 0) { diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index 17977fcb29..56c9db44cd 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -103,6 +103,8 @@ void EditorVisualProfiler::clear() { variables->clear(); //activate->set_pressed(false); + graph_limit = 1000.0f / CLAMP(int(EDITOR_GET("debugger/profiler_target_fps")), 1, 1000); + updating_frame = true; cursor_metric_edit->set_min(0); cursor_metric_edit->set_max(0); @@ -812,6 +814,8 @@ EditorVisualProfiler::EditorVisualProfiler() { int metric_size = CLAMP(int(EDITOR_GET("debugger/profiler_frame_history_size")), 60, 10000); frame_metrics.resize(metric_size); + graph_limit = 1000.0f / CLAMP(int(EDITOR_GET("debugger/profiler_target_fps")), 1, 1000); + frame_delay = memnew(Timer); frame_delay->set_wait_time(0.1); frame_delay->set_one_shot(true); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 3d3caf59eb..e13a984213 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -410,11 +410,13 @@ void EditorFileSystem::_scan_filesystem() { new_filesystem->parent = nullptr; ScannedDirectory *sd; + HashSet<String> *processed_files = nullptr; // On the first scan, the first_scan_root_dir is created in _first_scan_filesystem. if (first_scan) { sd = first_scan_root_dir; // Will be updated on scan. ResourceUID::get_singleton()->clear(); + processed_files = memnew(HashSet<String>()); } else { Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); sd = memnew(ScannedDirectory); @@ -422,14 +424,18 @@ void EditorFileSystem::_scan_filesystem() { nb_files_total = _scan_new_dir(sd, d); } - _process_file_system(sd, new_filesystem, sp); + _process_file_system(sd, new_filesystem, sp, processed_files); + if (first_scan) { + _process_removed_files(*processed_files); + } dep_update_list.clear(); file_cache.clear(); //clear caches, no longer needed if (first_scan) { memdelete(first_scan_root_dir); first_scan_root_dir = nullptr; + memdelete(processed_files); } else { //on the first scan this is done from the main thread after re-importing _save_filesystem_cache(); @@ -990,7 +996,7 @@ int EditorFileSystem::_scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da) return nb_files_total_scan; } -void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress) { +void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, HashSet<String> *r_processed_files) { p_dir->modified_time = FileAccess::get_modified_time(p_scan_dir->full_path); for (ScannedDirectory *scan_sub_dir : p_scan_dir->subdirs) { @@ -998,7 +1004,7 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir, sub_dir->parent = p_dir; sub_dir->name = scan_sub_dir->name; p_dir->subdirs.push_back(sub_dir); - _process_file_system(scan_sub_dir, sub_dir, p_progress); + _process_file_system(scan_sub_dir, sub_dir, p_progress, r_processed_files); } for (const String &scan_file : p_scan_dir->files) { @@ -1014,6 +1020,10 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir, fi->file = scan_file; p_dir->files.push_back(fi); + if (r_processed_files) { + r_processed_files->insert(path); + } + FileCache *fc = file_cache.getptr(path); uint64_t mt = FileAccess::get_modified_time(path); @@ -1139,6 +1149,20 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir, } } +void EditorFileSystem::_process_removed_files(const HashSet<String> &p_processed_files) { + for (const KeyValue<String, EditorFileSystem::FileCache> &kv : file_cache) { + if (!p_processed_files.has(kv.key)) { + if (ClassDB::is_parent_class(kv.value.type, SNAME("Script"))) { + // A script has been removed from disk since the last startup. The documentation needs to be updated. + // There's no need to add the path in update_script_paths since that is exclusively for updating global class names, + // which is handled in _first_scan_filesystem before the full scan to ensure plugins and autoloads can be created. + MutexLock update_script_lock(update_script_mutex); + update_script_paths_documentation.insert(kv.key); + } + } + } +} + void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress &p_progress) { uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path()); @@ -1206,7 +1230,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanPr int nb_files_dir = _scan_new_dir(&sd, d); p_progress.hi += nb_files_dir; diff_nb_files += nb_files_dir; - _process_file_system(&sd, efd, p_progress); + _process_file_system(&sd, efd, p_progress, nullptr); ItemAction ia; ia.action = ItemAction::ACTION_DIR_ADD; @@ -1872,7 +1896,12 @@ void EditorFileSystem::_update_script_classes() { EditorProgress *ep = nullptr; if (update_script_paths.size() > 1) { - ep = memnew(EditorProgress("update_scripts_classes", TTR("Registering global classes..."), update_script_paths.size())); + if (MessageQueue::get_singleton()->is_flushing()) { + // Use background progress when message queue is flushing. + ep = memnew(EditorProgress("update_scripts_classes", TTR("Registering global classes..."), update_script_paths.size(), false, true)); + } else { + ep = memnew(EditorProgress("update_scripts_classes", TTR("Registering global classes..."), update_script_paths.size())); + } } int step_count = 0; @@ -1911,7 +1940,12 @@ void EditorFileSystem::_update_script_documentation() { EditorProgress *ep = nullptr; if (update_script_paths_documentation.size() > 1) { - ep = memnew(EditorProgress("update_script_paths_documentation", TTR("Updating scripts documentation"), update_script_paths_documentation.size())); + if (MessageQueue::get_singleton()->is_flushing()) { + // Use background progress when message queue is flushing. + ep = memnew(EditorProgress("update_script_paths_documentation", TTR("Updating scripts documentation"), update_script_paths_documentation.size(), false, true)); + } else { + ep = memnew(EditorProgress("update_script_paths_documentation", TTR("Updating scripts documentation"), update_script_paths_documentation.size())); + } } int step_count = 0; diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 2ceb3fe4a5..7848ede8a7 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -239,7 +239,7 @@ class EditorFileSystem : public Node { HashSet<String> import_extensions; int _scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da); - void _process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress); + void _process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, HashSet<String> *p_processed_files); Thread thread_sources; bool scanning_changes = false; @@ -287,6 +287,7 @@ class EditorFileSystem : public Node { void _update_script_classes(); void _update_script_documentation(); void _process_update_pending(); + void _process_removed_files(const HashSet<String> &p_processed_files); Mutex update_scene_mutex; HashSet<String> update_scene_paths; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 1e5acce032..a1cae374aa 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1500,12 +1500,6 @@ void EditorInspectorSection::_notification(int p_what) { draw_string(font, text_offset, label, text_align, available, font_size, font_color, TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS); } - // Draw dropping highlight. - if (dropping && !vbox->is_visible_in_tree()) { - Color accent_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor)); - draw_rect(Rect2(Point2(), get_size()), accent_color, false); - } - // Draw section indentation. if (section_indent_style.is_valid() && section_indent > 0) { Rect2 indent_rect = Rect2(Vector2(), Vector2(indent_depth * section_indent_size, get_size().height)); @@ -1527,14 +1521,14 @@ void EditorInspectorSection::_notification(int p_what) { } break; case NOTIFICATION_MOUSE_ENTER: { - if (dropping || dropping_for_unfold) { + if (dropping_for_unfold) { dropping_unfold_timer->start(); } queue_redraw(); } break; case NOTIFICATION_MOUSE_EXIT: { - if (dropping || dropping_for_unfold) { + if (dropping_for_unfold) { dropping_unfold_timer->stop(); } queue_redraw(); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 29ee234883..fda1443000 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -310,7 +310,6 @@ class EditorInspectorSection : public Container { int level = 1; Timer *dropping_unfold_timer = nullptr; - bool dropping = false; bool dropping_for_unfold = false; HashSet<StringName> revertable_properties; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 32e6126225..f154cbd1e2 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -167,10 +167,6 @@ #include "modules/modules_enabled.gen.h" // For gdscript, mono. -#if defined(GLES3_ENABLED) -#include "drivers/gles3/rasterizer_gles3.h" -#endif - EditorNode *EditorNode::singleton = nullptr; static const String EDITOR_NODE_CONFIG_SECTION = "EditorNode"; @@ -179,7 +175,7 @@ static const String REMOVE_ANDROID_BUILD_TEMPLATE_MESSAGE = "The Android build t static const String INSTALL_ANDROID_BUILD_TEMPLATE_MESSAGE = "This will set up your project for gradle Android builds by installing the source template to \"%s\".\nNote that in order to make gradle builds instead of using pre-built APKs, the \"Use Gradle Build\" option should be enabled in the Android export preset."; bool EditorProgress::step(const String &p_state, int p_step, bool p_force_refresh) { - if (Thread::is_main_thread()) { + if (!force_background && Thread::is_main_thread()) { return EditorNode::progress_task_step(task, p_state, p_step, p_force_refresh); } else { EditorNode::progress_task_step_bg(task, p_step); @@ -187,17 +183,18 @@ bool EditorProgress::step(const String &p_state, int p_step, bool p_force_refres } } -EditorProgress::EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel) { - if (Thread::is_main_thread()) { +EditorProgress::EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel, bool p_force_background) { + if (!p_force_background && Thread::is_main_thread()) { EditorNode::progress_add_task(p_task, p_label, p_amount, p_can_cancel); } else { EditorNode::progress_add_task_bg(p_task, p_label, p_amount); } task = p_task; + force_background = p_force_background; } EditorProgress::~EditorProgress() { - if (Thread::is_main_thread()) { + if (!force_background && Thread::is_main_thread()) { EditorNode::progress_end_task(task); } else { EditorNode::progress_end_task_bg(task); @@ -5062,18 +5059,16 @@ String EditorNode::_get_system_info() const { driver_name = "Vulkan"; } else if (driver_name == "d3d12") { driver_name = "Direct3D 12"; -#if defined(GLES3_ENABLED) } else if (driver_name == "opengl3_angle") { driver_name = "OpenGL ES 3/ANGLE"; } else if (driver_name == "opengl3_es") { driver_name = "OpenGL ES 3"; } else if (driver_name == "opengl3") { - if (RasterizerGLES3::is_gles_over_gl()) { + if (OS::get_singleton()->get_gles_over_gl()) { driver_name = "OpenGL 3"; } else { driver_name = "OpenGL ES 3"; } -#endif } else if (driver_name == "metal") { driver_name = "Metal"; } @@ -7165,6 +7160,7 @@ EditorNode::EditorNode() { } main_menu = memnew(MenuBar); + main_menu->set_mouse_filter(Control::MOUSE_FILTER_STOP); title_bar->add_child(main_menu); main_menu->set_theme_type_variation("MainMenuBar"); main_menu->set_start_index(0); // Main menu, add to the start of global menu. @@ -7347,6 +7343,7 @@ EditorNode::EditorNode() { } main_editor_button_hb = memnew(HBoxContainer); + main_editor_button_hb->set_mouse_filter(Control::MOUSE_FILTER_STOP); title_bar->add_child(main_editor_button_hb); // Options are added and handled by DebuggerEditorPlugin. @@ -7441,11 +7438,13 @@ EditorNode::EditorNode() { title_bar->add_child(right_spacer); project_run_bar = memnew(EditorRunBar); + project_run_bar->set_mouse_filter(Control::MOUSE_FILTER_STOP); title_bar->add_child(project_run_bar); project_run_bar->connect("play_pressed", callable_mp(this, &EditorNode::_project_run_started)); project_run_bar->connect("stop_pressed", callable_mp(this, &EditorNode::_project_run_stopped)); HBoxContainer *right_menu_hb = memnew(HBoxContainer); + right_menu_hb->set_mouse_filter(Control::MOUSE_FILTER_STOP); title_bar->add_child(right_menu_hb); renderer = memnew(OptionButton); diff --git a/editor/editor_node.h b/editor/editor_node.h index bdf9b26a7a..e24bae73f0 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -124,9 +124,10 @@ class WindowWrapper; struct EditorProgress { String task; + bool force_background = false; bool step(const String &p_state, int p_step = -1, bool p_force_refresh = true); - EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel = false); + EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel = false, bool p_force_background = false); ~EditorProgress(); }; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index b5c11b574e..644916e83f 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -871,6 +871,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_remote_scene_tree", false, "") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_history_size", 3600, "60,10000,1") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_max_functions", 64, "16,512,1") + EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_target_fps", 60, "1,1000,1") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_scene_tree_refresh_interval", 1.0, "0.1,10,0.01,or_greater") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_inspect_refresh_interval", 0.2, "0.02,10,0.01,or_greater") EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/profile_native_calls", false, "") diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index 7aa19509e1..b6aa3c2215 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -115,6 +115,8 @@ void EditorFileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_file file_name = ProjectSettings::get_singleton()->localize_path(file_name); } } + selected_options = p_selected_options; + String f = files[0]; if (mode == FILE_MODE_OPEN_FILES) { emit_signal(SNAME("files_selected"), files); @@ -146,7 +148,6 @@ void EditorFileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_file } file->set_text(f); dir->set_text(f.get_base_dir()); - selected_options = p_selected_options; filter->select(p_filter); } diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index 52ba98b4d5..2de22238f4 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -174,15 +174,40 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i EditorDockManager::get_singleton()->focus_dock(NodeDock::get_singleton()); NodeDock::get_singleton()->show_groups(); } else if (p_id == BUTTON_UNIQUE) { - undo_redo->create_action(TTR("Disable Scene Unique Name")); - undo_redo->add_do_method(n, "set_unique_name_in_owner", false); - undo_redo->add_undo_method(n, "set_unique_name_in_owner", true); - undo_redo->add_do_method(this, "_update_tree"); - undo_redo->add_undo_method(this, "_update_tree"); - undo_redo->commit_action(); + bool ask_before_revoking_unique_name = EDITOR_GET("docks/scene_tree/ask_before_revoking_unique_name"); + revoke_node = n; + if (ask_before_revoking_unique_name) { + String msg = vformat(TTR("Revoke unique name for node \"%s\"?"), n->get_name()); + ask_before_revoke_checkbox->set_pressed(false); + revoke_dialog_label->set_text(msg); + revoke_dialog->reset_size(); + revoke_dialog->popup_centered(); + } else { + _revoke_unique_name(); + } } } +void SceneTreeEditor::_update_ask_before_revoking_unique_name() { + if (ask_before_revoke_checkbox->is_pressed()) { + EditorSettings::get_singleton()->set("docks/scene_tree/ask_before_revoking_unique_name", false); + ask_before_revoke_checkbox->set_pressed(false); + } + + _revoke_unique_name(); +} + +void SceneTreeEditor::_revoke_unique_name() { + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + + undo_redo->create_action(TTR("Disable Scene Unique Name")); + undo_redo->add_do_method(revoke_node, "set_unique_name_in_owner", false); + undo_redo->add_undo_method(revoke_node, "set_unique_name_in_owner", true); + undo_redo->add_do_method(this, "_update_tree"); + undo_redo->add_undo_method(this, "_update_tree"); + undo_redo->commit_action(); +} + void SceneTreeEditor::_toggle_visible(Node *p_node) { if (p_node->has_method("is_visible") && p_node->has_method("set_visible")) { bool v = bool(p_node->call("is_visible")); @@ -1620,6 +1645,18 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope update_node_tooltip_delay->set_one_shot(true); add_child(update_node_tooltip_delay); + revoke_dialog = memnew(ConfirmationDialog); + revoke_dialog->set_ok_button_text(TTR("Revoke")); + add_child(revoke_dialog); + revoke_dialog->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeEditor::_update_ask_before_revoking_unique_name)); + VBoxContainer *vb = memnew(VBoxContainer); + revoke_dialog->add_child(vb); + revoke_dialog_label = memnew(Label); + vb->add_child(revoke_dialog_label); + ask_before_revoke_checkbox = memnew(CheckBox(TTR("Don't Ask Again"))); + ask_before_revoke_checkbox->set_tooltip_text(TTR("This dialog can also be enabled/disabled in the Editor Settings: Docks > Scene Tree > Ask Before Revoking Unique Name.")); + vb->add_child(ask_before_revoke_checkbox); + script_types = memnew(List<StringName>); ClassDB::get_inheriters_from_class("Script", script_types); } diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h index b4d9644f16..9633993b8b 100644 --- a/editor/gui/scene_tree_editor.h +++ b/editor/gui/scene_tree_editor.h @@ -31,6 +31,7 @@ #ifndef SCENE_TREE_EDITOR_H #define SCENE_TREE_EDITOR_H +#include "scene/gui/check_box.h" #include "scene/gui/check_button.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" @@ -68,6 +69,11 @@ class SceneTreeEditor : public Control { AcceptDialog *error = nullptr; AcceptDialog *warning = nullptr; + ConfirmationDialog *revoke_dialog = nullptr; + Label *revoke_dialog_label = nullptr; + CheckBox *ask_before_revoke_checkbox = nullptr; + Node *revoke_node = nullptr; + bool auto_expand_selected = true; bool connect_to_script_mode = false; bool connecting_signal = false; @@ -144,6 +150,9 @@ class SceneTreeEditor : public Control { Vector<StringName> valid_types; + void _update_ask_before_revoking_unique_name(); + void _revoke_unique_name(); + public: // Public for use with callable_mp. void _update_tree(bool p_scroll_to_selected = false); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index b882112950..5cb558abbe 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -402,7 +402,17 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { track_editor->set_animation(anim, animation_is_readonly); Node *root = player->get_node_or_null(player->get_root_node()); - if (root) { + + // Player shouldn't access parent if it's the scene root. + if (!root || (player == get_tree()->get_edited_scene_root() && player->get_root_node() == SceneStringName(path_pp))) { + NodePath cached_root_path = player->get_path_to(get_cached_root_node()); + if (player->get_node_or_null(cached_root_path) != nullptr) { + player->set_root_node(cached_root_path); + } else { + player->set_root_node(SceneStringName(path_pp)); // No other choice, preventing crash. + } + } else { + cached_root_node_id = root->get_instance_id(); // Caching as `track_editor` can lose track of player's root node. track_editor->set_root(root); } } @@ -1886,6 +1896,10 @@ AnimationMixer *AnimationPlayerEditor::fetch_mixer_for_library() const { return original_node; } +Node *AnimationPlayerEditor::get_cached_root_node() const { + return Object::cast_to<Node>(ObjectDB::get_instance(cached_root_node_id)); +} + bool AnimationPlayerEditor::_validate_tracks(const Ref<Animation> p_anim) { bool is_valid = true; if (!p_anim.is_valid()) { diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 860d421b91..e4ca6c17c3 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -52,6 +52,7 @@ class AnimationPlayerEditor : public VBoxContainer { AnimationPlayerEditorPlugin *plugin = nullptr; AnimationMixer *original_node = nullptr; // For pinned mark in SceneTree. AnimationPlayer *player = nullptr; // For AnimationPlayerEditor, could be dummy. + ObjectID cached_root_node_id; bool is_dummy = false; enum { @@ -253,6 +254,7 @@ public: AnimationMixer *get_editing_node() const; AnimationPlayer *get_player() const; AnimationMixer *fetch_mixer_for_library() const; + Node *get_cached_root_node() const; static AnimationPlayerEditor *get_singleton() { return singleton; } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 054239d99f..bf8dab92f8 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -2995,8 +2995,8 @@ void VisualShaderEditor::_frame_title_popup_show(const Point2 &p_position, int p } frame_title_change_edit->set_text(node->get_title()); frame_title_change_popup->set_meta("id", p_node_id); - frame_title_change_popup->popup(); frame_title_change_popup->set_position(p_position); + frame_title_change_popup->popup(); // Select current text. frame_title_change_edit->grab_focus(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index baa77cb41d..9978c55d7b 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -4655,6 +4655,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true); EDITOR_DEF("interface/editors/derive_script_globals_by_name", true); EDITOR_DEF("docks/scene_tree/ask_before_deleting_related_animation_tracks", true); + EDITOR_DEF("docks/scene_tree/ask_before_revoking_unique_name", true); EDITOR_DEF("_use_favorites_root_selection", false); Resource::_update_configuration_warning = _update_configuration_warning; diff --git a/main/main.cpp b/main/main.cpp index f2f71c27a4..db5e6ec398 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2903,6 +2903,8 @@ Error Main::setup2(bool p_show_boot_logo) { Error err; display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, init_screen, context, err); if (err != OK || display_server == nullptr) { + String last_name = DisplayServer::get_create_function_name(display_driver_idx); + // We can't use this display server, try other ones as fallback. // Skip headless (always last registered) because that's not what users // would expect if they didn't request it explicitly. @@ -2910,6 +2912,9 @@ Error Main::setup2(bool p_show_boot_logo) { if (i == display_driver_idx) { continue; // Don't try the same twice. } + String name = DisplayServer::get_create_function_name(i); + WARN_PRINT(vformat("Display driver %s failed, falling back to %s.", last_name, name)); + display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, init_screen, context, err); if (err == OK && display_server != nullptr) { break; diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index d1d83fe4ce..2074d7228d 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -480,7 +480,7 @@ String DisplayServerWayland::clipboard_get_primary() const { for (String mime : text_mimes) { if (wayland_thread.primary_has_mime(mime)) { print_verbose(vformat("Selecting media type \"%s\" from offered types.", mime)); - wayland_thread.primary_get_mime(mime); + data = wayland_thread.primary_get_mime(mime); break; } } @@ -1349,23 +1349,39 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win rendering_driver = p_rendering_driver; + bool driver_found = false; + String executable_name = OS::get_singleton()->get_executable_path().get_file(); + #ifdef RD_ENABLED #ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { rendering_context = memnew(RenderingContextDriverVulkanWayland); } -#endif +#endif // VULKAN_ENABLED if (rendering_context) { if (rendering_context->initialize() != OK) { - ERR_PRINT(vformat("Could not initialize %s", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; r_error = ERR_CANT_CREATE; - return; + + if (p_rendering_driver == "vulkan") { + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" + "If you recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize Vulkan video driver"); + } + + ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); } + + driver_found = true; } -#endif +#endif // RD_ENABLED #ifdef GLES3_ENABLED if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") { @@ -1432,26 +1448,53 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); } else { r_error = ERR_UNAVAILABLE; + + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" + "If possible, consider updating your video card drivers or using the Vulkan driver.\n\n" + "You can enable the Vulkan driver by starting the engine from the\n" + "command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n" + "If you recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize OpenGL video driver"); + ERR_FAIL_MSG("Could not initialize OpenGL."); } } else { RasterizerGLES3::make_current(true); + driver_found = true; } } if (rendering_driver == "opengl3_es") { egl_manager = memnew(EGLManagerWaylandGLES); - if (egl_manager->initialize(wayland_thread.get_wl_display()) != OK) { + if (egl_manager->initialize(wayland_thread.get_wl_display()) != OK || egl_manager->open_display(wayland_thread.get_wl_display()) != OK) { memdelete(egl_manager); egl_manager = nullptr; r_error = ERR_CANT_CREATE; - ERR_FAIL_MSG("Could not initialize GLES3."); + + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required OpenGL ES 3.0 version.\n\n" + "If possible, consider updating your video card drivers or using the Vulkan driver.\n\n" + "You can enable the Vulkan driver by starting the engine from the\n" + "command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n" + "If you recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize OpenGL ES video driver"); + + ERR_FAIL_MSG("Could not initialize OpenGL ES."); } RasterizerGLES3::make_current(false); + driver_found = true; } } + + if (!driver_found) { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Video driver not found."); + } #endif // GLES3_ENABLED cursor_set_shape(CURSOR_BUSY); @@ -1482,12 +1525,12 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win RendererCompositorRD::make_current(); } -#endif +#endif // RD_ENABLED #ifdef DBUS_ENABLED portal_desktop = memnew(FreeDesktopPortalDesktop); screensaver = memnew(FreeDesktopScreenSaver); -#endif +#endif // DBUS_ENABLED screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index e602963c54..840cadace3 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -5428,25 +5428,6 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() { DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) { DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, r_error)); - if (r_error != OK) { - if (p_rendering_driver == "vulkan") { - String executable_name = OS::get_singleton()->get_executable_path().get_file(); - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" - "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize Vulkan video driver"); - } else { - OS::get_singleton()->alert( - "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" - "If possible, consider updating your video card drivers.\n\n" - "If you recently updated your video card drivers, try rebooting.", - "Unable to initialize OpenGL video driver"); - } - } return ds; } @@ -6160,25 +6141,40 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode rendering_driver = p_rendering_driver; bool driver_found = false; + String executable_name = OS::get_singleton()->get_executable_path().get_file(); + + // Initialize context and rendering device. + #if defined(RD_ENABLED) #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { rendering_context = memnew(RenderingContextDriverVulkanX11); } -#endif +#endif // VULKAN_ENABLED if (rendering_context) { if (rendering_context->initialize() != OK) { - ERR_PRINT(vformat("Could not initialize %s", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; r_error = ERR_CANT_CREATE; - return; + + if (p_rendering_driver == "vulkan") { + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" + "If you recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize Vulkan video driver"); + } + + ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); } driver_found = true; } -#endif - // Initialize context and rendering device. +#endif // RD_ENABLED + #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") { if (getenv("DRI_PRIME") == nullptr) { @@ -6234,6 +6230,16 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); } else { r_error = ERR_UNAVAILABLE; + + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" + "If possible, consider updating your video card drivers or using the Vulkan driver.\n\n" + "You can enable the Vulkan driver by starting the engine from the\n" + "command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n" + "If you recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize OpenGL video driver"); + ERR_FAIL_MSG("Could not initialize OpenGL."); } } else { @@ -6244,20 +6250,28 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode if (rendering_driver == "opengl3_es") { gl_manager_egl = memnew(GLManagerEGL_X11); - if (gl_manager_egl->initialize() != OK) { + if (gl_manager_egl->initialize() != OK || gl_manager_egl->open_display(x11_display) != OK) { memdelete(gl_manager_egl); gl_manager_egl = nullptr; r_error = ERR_UNAVAILABLE; - ERR_FAIL_MSG("Could not initialize OpenGLES."); + + OS::get_singleton()->alert( + "Your video card drivers seem not to support the required OpenGL ES 3.0 version.\n\n" + "If possible, consider updating your video card drivers.\n\n" + "If you recently updated your video card drivers, try rebooting.", + "Unable to initialize OpenGL ES video driver"); + + ERR_FAIL_MSG("Could not initialize OpenGL ES."); } driver_found = true; RasterizerGLES3::make_current(false); } -#endif +#endif // GLES3_ENABLED + if (!driver_found) { r_error = ERR_UNAVAILABLE; - ERR_FAIL_MSG("Video driver not found"); + ERR_FAIL_MSG("Video driver not found."); } Point2i window_position; @@ -6298,7 +6312,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode RendererCompositorRD::make_current(); } -#endif +#endif // RD_ENABLED { //set all event master mask @@ -6451,7 +6465,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); portal_desktop = memnew(FreeDesktopPortalDesktop); -#endif +#endif // DBUS_ENABLED + XSetErrorHandler(&default_window_error_handler); r_error = OK; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 602ca5f52e..50ebe7077f 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -522,7 +522,7 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) { if (!item.has("name") || !item.has("values") || !item.has("default")) { continue; } - event_handler->add_option(pfdc, item["name"], item["values"], item["default_idx"]); + event_handler->add_option(pfdc, item["name"], item["values"], item["default"]); } event_handler->set_root(fd->root); @@ -625,62 +625,41 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) { } } if (fd->callback.is_valid()) { - if (fd->options_in_cb) { - Variant v_result = true; - Variant v_files = file_names; - Variant v_index = index; - Variant v_opt = options; - const Variant *cb_args[4] = { &v_result, &v_files, &v_index, &v_opt }; - - fd->callback.call_deferredp(cb_args, 4); - } else { - Variant v_result = true; - Variant v_files = file_names; - Variant v_index = index; - const Variant *cb_args[3] = { &v_result, &v_files, &v_index }; - - fd->callback.call_deferredp(cb_args, 3); - } + MutexLock lock(ds->file_dialog_mutex); + FileDialogCallback cb; + cb.callback = fd->callback; + cb.status = true; + cb.files = file_names; + cb.index = index; + cb.options = options; + cb.opt_in_cb = fd->options_in_cb; + ds->pending_cbs.push_back(cb); } } else { if (fd->callback.is_valid()) { - if (fd->options_in_cb) { - Variant v_result = false; - Variant v_files = Vector<String>(); - Variant v_index = 0; - Variant v_opt = Dictionary(); - const Variant *cb_args[4] = { &v_result, &v_files, &v_index, &v_opt }; - - fd->callback.call_deferredp(cb_args, 4); - } else { - Variant v_result = false; - Variant v_files = Vector<String>(); - Variant v_index = 0; - const Variant *cb_args[3] = { &v_result, &v_files, &v_index }; - - fd->callback.call_deferredp(cb_args, 3); - } + MutexLock lock(ds->file_dialog_mutex); + FileDialogCallback cb; + cb.callback = fd->callback; + cb.status = false; + cb.files = Vector<String>(); + cb.index = index; + cb.options = options; + cb.opt_in_cb = fd->options_in_cb; + ds->pending_cbs.push_back(cb); } } pfd->Release(); } else { if (fd->callback.is_valid()) { - if (fd->options_in_cb) { - Variant v_result = false; - Variant v_files = Vector<String>(); - Variant v_index = 0; - Variant v_opt = Dictionary(); - const Variant *cb_args[4] = { &v_result, &v_files, &v_index, &v_opt }; - - fd->callback.call_deferredp(cb_args, 4); - } else { - Variant v_result = false; - Variant v_files = Vector<String>(); - Variant v_index = 0; - const Variant *cb_args[3] = { &v_result, &v_files, &v_index }; - - fd->callback.call_deferredp(cb_args, 3); - } + MutexLock lock(ds->file_dialog_mutex); + FileDialogCallback cb; + cb.callback = fd->callback; + cb.status = false; + cb.files = Vector<String>(); + cb.index = 0; + cb.options = Dictionary(); + cb.opt_in_cb = fd->options_in_cb; + ds->pending_cbs.push_back(cb); } } { @@ -768,6 +747,34 @@ Error DisplayServerWindows::_file_dialog_with_options_show(const String &p_title return OK; } +void DisplayServerWindows::process_file_dialog_callbacks() { + MutexLock lock(file_dialog_mutex); + while (!pending_cbs.is_empty()) { + FileDialogCallback cb = pending_cbs.front()->get(); + pending_cbs.pop_front(); + + if (cb.opt_in_cb) { + Variant ret; + Callable::CallError ce; + const Variant *args[4] = { &cb.status, &cb.files, &cb.index, &cb.options }; + + cb.callback.callp(args, 4, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(cb.callback, args, 4, ce))); + } + } else { + Variant ret; + Callable::CallError ce; + const Variant *args[3] = { &cb.status, &cb.files, &cb.index }; + + cb.callback.callp(args, 3, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(cb.callback, args, 3, ce))); + } + } + } +} + void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) { _THREAD_SAFE_METHOD_ @@ -3190,6 +3197,7 @@ void DisplayServerWindows::process_events() { memdelete(E->get()); E->erase(); } + process_file_dialog_callbacks(); } void DisplayServerWindows::force_process_and_drop_events() { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 3deb7ac8b0..54e1c9681d 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -572,6 +572,16 @@ class DisplayServerWindows : public DisplayServer { Mutex file_dialog_mutex; List<FileDialogData *> file_dialogs; HashMap<HWND, FileDialogData *> file_dialog_wnd; + struct FileDialogCallback { + Callable callback; + Variant status; + Variant files; + Variant index; + Variant options; + bool opt_in_cb = false; + }; + List<FileDialogCallback> pending_cbs; + void process_file_dialog_callbacks(); static void _thread_fd_monitor(void *p_ud); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 1a1aa5ccb0..373488b0fc 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -124,6 +124,8 @@ void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int file_name = ProjectSettings::get_singleton()->localize_path(file_name); } } + selected_options = p_selected_options; + String f = files[0]; if (mode == FILE_MODE_OPEN_FILES) { emit_signal(SNAME("files_selected"), files); @@ -155,7 +157,6 @@ void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int } file->set_text(f); dir->set_text(f.get_base_dir()); - selected_options = p_selected_options; filter->select(p_filter); } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index df668aa496..c2818edd9c 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -68,10 +68,15 @@ void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) { int cc = caret_column; PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); - for (int i = words.size() - 2; i >= 0; i = i - 2) { - if (words[i] < cc) { - cc = words[i]; - break; + if (words.is_empty() || cc <= words[0]) { + // Move to the start when there are no more words. + cc = 0; + } else { + for (int i = words.size() - 2; i >= 0; i = i - 2) { + if (words[i] < cc) { + cc = words[i]; + break; + } } } @@ -101,10 +106,15 @@ void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) { int cc = caret_column; PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); - for (int i = 1; i < words.size(); i = i + 2) { - if (words[i] > cc) { - cc = words[i]; - break; + if (words.is_empty() || cc >= words[words.size() - 1]) { + // Move to the end when there are no more words. + cc = text.length(); + } else { + for (int i = 1; i < words.size(); i = i + 2) { + if (words[i] > cc) { + cc = words[i]; + break; + } } } @@ -159,10 +169,15 @@ void LineEdit::_backspace(bool p_word, bool p_all_to_left) { int cc = caret_column; PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); - for (int i = words.size() - 2; i >= 0; i = i - 2) { - if (words[i] < cc) { - cc = words[i]; - break; + if (words.is_empty() || cc <= words[0]) { + // Delete to the start when there are no more words. + cc = 0; + } else { + for (int i = words.size() - 2; i >= 0; i = i - 2) { + if (words[i] < cc) { + cc = words[i]; + break; + } } } @@ -198,10 +213,15 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) { if (p_word) { int cc = caret_column; PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); - for (int i = 1; i < words.size(); i = i + 2) { - if (words[i] > cc) { - cc = words[i]; - break; + if (words.is_empty() || cc >= words[words.size() - 1]) { + // Delete to the end when there are no more words. + cc = text.length(); + } else { + for (int i = 1; i < words.size(); i = i + 2) { + if (words[i] > cc) { + cc = words[i]; + break; + } } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index a2f39af858..c4b33fd889 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2393,7 +2393,7 @@ void TextEdit::_move_caret_left(bool p_select, bool p_move_by_word) { } else { PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(get_caret_line(i))->get_rid()); if (words.is_empty() || cc <= words[0]) { - // This solves the scenario where there are no words but glyfs that can be ignored. + // Move to the start when there are no more words. cc = 0; } else { for (int j = words.size() - 2; j >= 0; j = j - 2) { @@ -2450,7 +2450,7 @@ void TextEdit::_move_caret_right(bool p_select, bool p_move_by_word) { } else { PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(get_caret_line(i))->get_rid()); if (words.is_empty() || cc >= words[words.size() - 1]) { - // This solves the scenario where there are no words but glyfs that can be ignored. + // Move to the end when there are no more words. cc = text[get_caret_line(i)].length(); } else { for (int j = 1; j < words.size(); j = j + 2) { @@ -2666,7 +2666,7 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) { // Get a list with the indices of the word bounds of the given text line. const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(get_caret_line(caret_index))->get_rid()); if (words.is_empty() || column <= words[0]) { - // If "words" is empty, meaning no words are left, we can remove everything until the beginning of the line. + // Delete to the start when there are no more words. column = 0; } else { // Otherwise search for the first word break that is smaller than the index from we're currently deleting. @@ -2731,10 +2731,15 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) { int column = get_caret_column(caret_index); PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid()); - for (int j = 1; j < words.size(); j = j + 2) { - if (words[j] > column) { - column = words[j]; - break; + if (words.is_empty() || column >= words[words.size() - 1]) { + // Delete to the end when there are no more words. + column = text[get_caret_line(i)].length(); + } else { + for (int j = 1; j < words.size(); j = j + 2) { + if (words[j] > column) { + column = words[j]; + break; + } } } diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index 7d4ce6888f..2087989102 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -1250,7 +1250,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RS::SkyMode sky_mode = sky->mode; if (sky_mode == RS::SKY_MODE_AUTOMATIC) { - if (shader_data->uses_time || shader_data->uses_position) { + if ((shader_data->uses_time || shader_data->uses_position) && sky->radiance_size == 256) { update_single_frame = true; sky_mode = RS::SKY_MODE_REALTIME; } else if (shader_data->uses_light || shader_data->ubo_size > 0) { diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index 69e27fe7a0..46a5046b21 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -4232,6 +4232,18 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_caret_line(0) == 0); CHECK(text_edit->get_caret_column(0) == 4); text_edit->remove_secondary_carets(); + + // Remove when there are no words, only symbols. + text_edit->set_text("#{}"); + text_edit->set_caret_line(0); + text_edit->set_caret_column(3); + + SEND_GUI_ACTION("ui_text_backspace_word"); + CHECK(text_edit->get_viewport()->is_input_handled()); + CHECK_FALSE(text_edit->has_selection()); + CHECK(text_edit->get_text() == ""); + CHECK(text_edit->get_caret_line(0) == 0); + CHECK(text_edit->get_caret_column(0) == 0); } SUBCASE("[TextEdit] ui_text_backspace_word same line") { @@ -4891,6 +4903,18 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_caret_line(0) == 0); CHECK(text_edit->get_caret_column(0) == 2); text_edit->remove_secondary_carets(); + + // Remove when there are no words, only symbols. + text_edit->set_text("#{}"); + text_edit->set_caret_line(0); + text_edit->set_caret_column(0); + + SEND_GUI_ACTION("ui_text_delete_word"); + CHECK(text_edit->get_viewport()->is_input_handled()); + CHECK_FALSE(text_edit->has_selection()); + CHECK(text_edit->get_text() == ""); + CHECK(text_edit->get_caret_line(0) == 0); + CHECK(text_edit->get_caret_column(0) == 0); } SUBCASE("[TextEdit] ui_text_delete_word same line") { @@ -5301,6 +5325,16 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + + // Move when there are no words, only symbols. + text_edit->set_text("#{}"); + text_edit->set_caret_line(0); + text_edit->set_caret_column(3); + + SEND_GUI_ACTION("ui_text_caret_word_left"); + CHECK(text_edit->get_viewport()->is_input_handled()); + CHECK(text_edit->get_caret_line(0) == 0); + CHECK(text_edit->get_caret_column(0) == 0); } SUBCASE("[TextEdit] ui_text_caret_left") { @@ -5563,6 +5597,16 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { SIGNAL_CHECK("caret_changed", empty_signal_args); SIGNAL_CHECK_FALSE("text_changed"); SIGNAL_CHECK_FALSE("lines_edited_from"); + + // Move when there are no words, only symbols. + text_edit->set_text("#{}"); + text_edit->set_caret_line(0); + text_edit->set_caret_column(0); + + SEND_GUI_ACTION("ui_text_caret_word_right"); + CHECK(text_edit->get_viewport()->is_input_handled()); + CHECK(text_edit->get_caret_line(0) == 0); + CHECK(text_edit->get_caret_column(0) == 3); } SUBCASE("[TextEdit] ui_text_caret_right") { |
