summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/os/os.h3
-rw-r--r--core/string/string_name.cpp100
-rw-r--r--core/string/string_name.h11
-rw-r--r--doc/classes/EditorSettings.xml3
-rw-r--r--drivers/gles3/rasterizer_gles3.h1
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp2
-rw-r--r--editor/debugger/editor_visual_profiler.cpp4
-rw-r--r--editor/editor_file_system.cpp46
-rw-r--r--editor/editor_file_system.h3
-rw-r--r--editor/editor_inspector.cpp10
-rw-r--r--editor/editor_inspector.h1
-rw-r--r--editor/editor_node.cpp21
-rw-r--r--editor/editor_node.h3
-rw-r--r--editor/editor_settings.cpp1
-rw-r--r--editor/gui/editor_file_dialog.cpp3
-rw-r--r--editor/gui/scene_tree_editor.cpp49
-rw-r--r--editor/gui/scene_tree_editor.h9
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp16
-rw-r--r--editor/plugins/animation_player_editor_plugin.h2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2
-rw-r--r--editor/scene_tree_dock.cpp1
-rw-r--r--main/main.cpp5
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.cpp61
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp75
-rw-r--r--platform/windows/display_server_windows.cpp106
-rw-r--r--platform/windows/display_server_windows.h10
-rw-r--r--scene/gui/file_dialog.cpp3
-rw-r--r--scene/gui/line_edit.cpp52
-rw-r--r--scene/gui/text_edit.cpp19
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp2
-rw-r--r--tests/scene/test_text_edit.h44
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") {