summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/android_input_handler.cpp9
-rw-r--r--platform/android/android_input_handler.h4
-rw-r--r--platform/android/android_keys_utils.h6
-rw-r--r--platform/android/display_server_android.cpp11
-rw-r--r--platform/android/display_server_android.h4
-rw-r--r--platform/android/export/export_plugin.cpp154
-rw-r--r--platform/android/export/export_plugin.h22
-rw-r--r--platform/android/export/gradle_export_util.cpp2
-rw-r--r--platform/android/java/app/config.gradle8
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt19
-rw-r--r--platform/android/java/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--platform/android/java/lib/AndroidManifest.xml3
-rw-r--r--platform/android/java/lib/build.gradle13
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt84
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java31
-rw-r--r--platform/android/java_godot_lib_jni.cpp63
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/android/java_godot_view_wrapper.cpp2
-rw-r--r--platform/android/jni_utils.cpp16
-rw-r--r--platform/android/os_android.cpp9
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp4
-rw-r--r--platform/android/vulkan/vulkan_context_android.cpp4
-rw-r--r--platform/android/vulkan/vulkan_context_android.h4
-rw-r--r--platform/ios/display_server_ios.h8
-rw-r--r--platform/ios/display_server_ios.mm12
-rw-r--r--platform/ios/export/export_plugin.cpp174
-rw-r--r--platform/ios/godot_view.mm13
-rw-r--r--platform/ios/os_ios.mm9
-rw-r--r--platform/ios/vulkan_context_ios.h4
-rw-r--r--platform/ios/vulkan_context_ios.mm4
-rw-r--r--platform/linuxbsd/SCsub10
-rw-r--r--platform/linuxbsd/detect.py1
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp4
-rw-r--r--platform/linuxbsd/freedesktop_screensaver.cpp2
-rw-r--r--platform/linuxbsd/godot_linuxbsd.cpp1
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp45
-rw-r--r--platform/linuxbsd/os_linuxbsd.h2
-rw-r--r--platform/linuxbsd/platform_config.h2
-rw-r--r--platform/linuxbsd/x11/SCsub21
-rw-r--r--platform/linuxbsd/x11/detect_prime_x11.cpp (renamed from platform/linuxbsd/detect_prime_x11.cpp)28
-rw-r--r--platform/linuxbsd/x11/detect_prime_x11.h (renamed from platform/linuxbsd/detect_prime_x11.h)0
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp (renamed from platform/linuxbsd/display_server_x11.cpp)62
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h (renamed from platform/linuxbsd/display_server_x11.h)13
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp (renamed from platform/linuxbsd/gl_manager_x11.cpp)43
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.h (renamed from platform/linuxbsd/gl_manager_x11.h)2
-rw-r--r--platform/linuxbsd/x11/key_mapping_x11.cpp (renamed from platform/linuxbsd/key_mapping_x11.cpp)0
-rw-r--r--platform/linuxbsd/x11/key_mapping_x11.h (renamed from platform/linuxbsd/key_mapping_x11.h)0
-rw-r--r--platform/linuxbsd/x11/vulkan_context_x11.cpp (renamed from platform/linuxbsd/vulkan_context_x11.cpp)4
-rw-r--r--platform/linuxbsd/x11/vulkan_context_x11.h (renamed from platform/linuxbsd/vulkan_context_x11.h)4
-rw-r--r--platform/macos/detect.py24
-rw-r--r--platform/macos/display_server_macos.h6
-rw-r--r--platform/macos/display_server_macos.mm155
-rw-r--r--platform/macos/export/export_plugin.cpp38
-rw-r--r--platform/macos/export/export_plugin.h2
-rw-r--r--platform/macos/gl_manager_macos_legacy.h2
-rw-r--r--platform/macos/gl_manager_macos_legacy.mm9
-rw-r--r--platform/macos/godot_application_delegate.mm4
-rw-r--r--platform/macos/godot_window_delegate.mm14
-rw-r--r--platform/macos/os_macos.mm9
-rw-r--r--platform/macos/platform_config.h2
-rw-r--r--platform/macos/vulkan_context_macos.h4
-rw-r--r--platform/macos/vulkan_context_macos.mm3
-rw-r--r--platform/uwp/export/export_plugin.cpp8
-rw-r--r--platform/uwp/export/export_plugin.h2
-rw-r--r--platform/web/SCsub1
-rw-r--r--platform/web/display_server_web.cpp42
-rw-r--r--platform/web/display_server_web.h5
-rw-r--r--platform/web/godot_webgl2.h17
-rw-r--r--platform/web/js/engine/config.js2
-rw-r--r--platform/web/js/libs/library_godot_webgl2.js52
-rw-r--r--platform/web/package-lock.json12
-rw-r--r--platform/web/web_main.cpp36
-rw-r--r--platform/windows/SCsub25
-rw-r--r--platform/windows/console_wrapper_windows.cpp181
-rw-r--r--platform/windows/detect.py12
-rw-r--r--platform/windows/display_server_windows.cpp110
-rw-r--r--platform/windows/display_server_windows.h7
-rw-r--r--platform/windows/export/export_plugin.cpp195
-rw-r--r--platform/windows/export/export_plugin.h4
-rw-r--r--platform/windows/gl_manager_windows.cpp69
-rw-r--r--platform/windows/gl_manager_windows.h13
-rw-r--r--platform/windows/godot_res_wrap.rc33
-rw-r--r--platform/windows/joypad_windows.cpp2
-rw-r--r--platform/windows/os_windows.cpp35
-rw-r--r--platform/windows/os_windows.h4
-rw-r--r--platform/windows/platform_config.h2
-rw-r--r--platform/windows/vulkan_context_win.h4
90 files changed, 1484 insertions, 613 deletions
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index 454bcd2eda..c0b098cd7f 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -118,7 +118,7 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycod
Input::get_singleton()->parse_input_event(ev);
}
-void AndroidInputHandler::_parse_all_touch(bool p_pressed) {
+void AndroidInputHandler::_parse_all_touch(bool p_pressed, bool p_double_tap) {
if (touch.size()) {
//end all if exist
for (int i = 0; i < touch.size(); i++) {
@@ -127,17 +127,18 @@ void AndroidInputHandler::_parse_all_touch(bool p_pressed) {
ev->set_index(touch[i].id);
ev->set_pressed(p_pressed);
ev->set_position(touch[i].pos);
+ ev->set_double_tap(p_double_tap);
Input::get_singleton()->parse_input_event(ev);
}
}
}
void AndroidInputHandler::_release_all_touch() {
- _parse_all_touch(false);
+ _parse_all_touch(false, false);
touch.clear();
}
-void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points) {
+void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap) {
switch (p_event) {
case AMOTION_EVENT_ACTION_DOWN: { //gesture begin
// Release any remaining touches or mouse event
@@ -151,7 +152,7 @@ void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const
}
//send touch
- _parse_all_touch(true);
+ _parse_all_touch(true, p_double_tap);
} break;
case AMOTION_EVENT_ACTION_MOVE: { //motion
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index 88490f0407..4da8a910c0 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -87,13 +87,13 @@ private:
void _release_mouse_event_info(bool p_source_mouse_relative = false);
- void _parse_all_touch(bool p_pressed);
+ void _parse_all_touch(bool p_pressed, bool p_double_tap);
void _release_all_touch();
public:
void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative);
- void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points);
+ void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap);
void process_magnify(Point2 p_pos, float p_factor);
void process_pan(Point2 p_pos, Vector2 p_delta);
void process_joy_event(JoypadEvent p_event);
diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h
index 5ec3ee17aa..bc633aeade 100644
--- a/platform/android/android_keys_utils.h
+++ b/platform/android/android_keys_utils.h
@@ -43,7 +43,6 @@ struct AndroidGodotCodePair {
static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_UNKNOWN, Key::UNKNOWN }, // (0) Unknown key code.
- { AKEYCODE_HOME, Key::HOME }, // (3) Home key.
{ AKEYCODE_BACK, Key::BACK }, // (4) Back key.
{ AKEYCODE_0, Key::KEY_0 }, // (7) '0' key.
{ AKEYCODE_1, Key::KEY_1 }, // (8) '1' key.
@@ -63,6 +62,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_DPAD_RIGHT, Key::RIGHT }, // (22) Directional Pad Right key.
{ AKEYCODE_VOLUME_UP, Key::VOLUMEUP }, // (24) Volume Up key.
{ AKEYCODE_VOLUME_DOWN, Key::VOLUMEDOWN }, // (25) Volume Down key.
+ { AKEYCODE_POWER, Key::STANDBY }, // (26) Power key.
{ AKEYCODE_CLEAR, Key::CLEAR }, // (28) Clear key.
{ AKEYCODE_A, Key::A }, // (29) 'A' key.
{ AKEYCODE_B, Key::B }, // (30) 'B' key.
@@ -98,6 +98,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_SHIFT_RIGHT, Key::SHIFT }, // (60) Right Shift modifier key.
{ AKEYCODE_TAB, Key::TAB }, // (61) Tab key.
{ AKEYCODE_SPACE, Key::SPACE }, // (62) Space key.
+ { AKEYCODE_ENVELOPE, Key::LAUNCHMAIL }, // (65) Envelope special function key.
{ AKEYCODE_ENTER, Key::ENTER }, // (66) Enter key.
{ AKEYCODE_DEL, Key::BACKSPACE }, // (67) Backspace key.
{ AKEYCODE_GRAVE, Key::QUOTELEFT }, // (68) '`' (backtick) key.
@@ -114,6 +115,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_MENU, Key::MENU }, // (82) Menu key.
{ AKEYCODE_SEARCH, Key::SEARCH }, // (84) Search key.
{ AKEYCODE_MEDIA_STOP, Key::MEDIASTOP }, // (86) Stop media key.
+ { AKEYCODE_MEDIA_NEXT, Key::MEDIANEXT }, // (87) Play Next media key.
{ AKEYCODE_MEDIA_PREVIOUS, Key::MEDIAPREVIOUS }, // (88) Play Previous media key.
{ AKEYCODE_PAGE_UP, Key::PAGEUP }, // (92) Page Up key.
{ AKEYCODE_PAGE_DOWN, Key::PAGEDOWN }, // (93) Page Down key.
@@ -127,6 +129,8 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_META_RIGHT, Key::META }, // (118) Right Meta modifier key.
{ AKEYCODE_SYSRQ, Key::PRINT }, // (120) System Request / Print Screen key.
{ AKEYCODE_BREAK, Key::PAUSE }, // (121) Break / Pause key.
+ { AKEYCODE_MOVE_HOME, Key::HOME }, // (122) Home Movement key.
+ { AKEYCODE_MOVE_END, Key::END }, // (123) End Movement key.
{ AKEYCODE_INSERT, Key::INSERT }, // (124) Insert key.
{ AKEYCODE_FORWARD, Key::FORWARD }, // (125) Forward key.
{ AKEYCODE_MEDIA_PLAY, Key::MEDIAPLAY }, // (126) Play media key.
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 6f8efbf069..967f5c7dae 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -321,6 +321,11 @@ int64_t DisplayServerAndroid::window_get_native_handle(HandleType p_handle_type,
case WINDOW_VIEW: {
return 0; // Not supported.
}
+#ifdef GLES3_ENABLED
+ case OPENGL_CONTEXT: {
+ return eglGetCurrentContext();
+ }
+#endif
default: {
return 0;
}
@@ -440,8 +445,8 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
if (r_error != OK) {
OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver");
}
@@ -485,7 +490,7 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) {
rect_changed_callback.callp(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce);
}
-DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
rendering_driver = p_rendering_driver;
// TODO: rendering_driver is broken, change when different drivers are supported again
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 6e14ba3e23..a6bc88e048 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -194,7 +194,7 @@ public:
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_android_driver();
@@ -204,7 +204,7 @@ public:
virtual Point2i mouse_get_position() const override;
virtual MouseButton mouse_get_button_state() const override;
- DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerAndroid();
};
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 6426f95b42..c3fba625c6 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -401,7 +401,7 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
}
}
- if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) {
+ if (EDITOR_GET("export/android/shutdown_adb_on_exit")) {
String adb = get_adb_path();
if (!FileAccess::exists(adb)) {
return; //adb not configured
@@ -419,7 +419,7 @@ String EditorExportPlatformAndroid::get_project_name(const String &p_name) const
if (!p_name.is_empty()) {
aname = p_name;
} else {
- aname = ProjectSettings::get_singleton()->get("application/config/name");
+ aname = GLOBAL_GET("application/config/name");
}
if (aname.is_empty()) {
@@ -431,7 +431,7 @@ String EditorExportPlatformAndroid::get_project_name(const String &p_name) const
String EditorExportPlatformAndroid::get_package_name(const String &p_package) const {
String pname = p_package;
- String basename = ProjectSettings::get_singleton()->get("application/config/name");
+ String basename = GLOBAL_GET("application/config/name");
basename = basename.to_lower();
String name;
@@ -585,12 +585,13 @@ zip_fileinfo EditorExportPlatformAndroid::get_zip_fileinfo() {
return zipfi;
}
-Vector<String> EditorExportPlatformAndroid::get_abis() {
- Vector<String> abis;
- abis.push_back("armeabi-v7a");
- abis.push_back("arm64-v8a");
- abis.push_back("x86");
- abis.push_back("x86_64");
+Vector<EditorExportPlatformAndroid::ABI> EditorExportPlatformAndroid::get_abis() {
+ // Should have the same order and size as get_archs.
+ Vector<ABI> abis;
+ abis.push_back(ABI("armeabi-v7a", "arm32"));
+ abis.push_back(ABI("arm64-v8a", "arm64"));
+ abis.push_back(ABI("x86", "x86_32"));
+ abis.push_back(ABI("x86_64", "x86_64"));
return abis;
}
@@ -687,14 +688,20 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj
return FAILED;
}
APKExportData *ed = static_cast<APKExportData *>(p_userdata);
- Vector<String> abis = get_abis();
+ Vector<ABI> abis = get_abis();
bool exported = false;
for (int i = 0; i < p_so.tags.size(); ++i) {
// shared objects can be fat (compatible with multiple ABIs)
- int abi_index = abis.find(p_so.tags[i]);
+ int abi_index = -1;
+ for (int j = 0; j < abis.size(); ++j) {
+ if (abis[j].abi == p_so.tags[i] || abis[j].arch == p_so.tags[i]) {
+ abi_index = j;
+ break;
+ }
+ }
if (abi_index != -1) {
exported = true;
- String abi = abis[abi_index];
+ String abi = abis[abi_index].abi;
String dst_path = String("lib").path_join(abi).path_join(p_so.path.get_file());
Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path);
Error store_err = store_in_apk(ed, dst_path, array);
@@ -702,9 +709,7 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj
}
}
if (!exported) {
- String abis_string = String(" ").join(abis);
- String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string;
- ERR_PRINT(err);
+ ERR_PRINT("Cannot determine architecture for library \"" + p_so.path + "\". One of the supported architectures must be used as a tag: " + join_abis(abis, " ", true));
return FAILED;
}
return OK;
@@ -725,16 +730,22 @@ Error EditorExportPlatformAndroid::ignore_apk_file(void *p_userdata, const Strin
Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const SharedObject &p_so) {
ERR_FAIL_COND_V_MSG(!p_so.path.get_file().begins_with("lib"), FAILED,
"Android .so file names must start with \"lib\", but got: " + p_so.path);
- Vector<String> abis = get_abis();
+ Vector<ABI> abis = get_abis();
CustomExportData *export_data = static_cast<CustomExportData *>(p_userdata);
bool exported = false;
for (int i = 0; i < p_so.tags.size(); ++i) {
- int abi_index = abis.find(p_so.tags[i]);
+ int abi_index = -1;
+ for (int j = 0; j < abis.size(); ++j) {
+ if (abis[j].abi == p_so.tags[i] || abis[j].arch == p_so.tags[i]) {
+ abi_index = j;
+ break;
+ }
+ }
if (abi_index != -1) {
exported = true;
String base = "res://android/build/libs";
String type = export_data->debug ? "debug" : "release";
- String abi = abis[abi_index];
+ String abi = abis[abi_index].abi;
String filename = p_so.path.get_file();
String dst_path = base.path_join(type).path_join(abi).path_join(filename);
Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path);
@@ -745,7 +756,7 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared
}
}
ERR_FAIL_COND_V_MSG(!exported, FAILED,
- "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + String(" ").join(abis));
+ "Cannot determine architecture for library \"" + p_so.path + "\". One of the supported architectures must be used as a tag:" + join_abis(abis, " ", true));
return OK;
}
@@ -791,7 +802,7 @@ void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset>
}
void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug) {
- print_verbose("Building temporary manifest..");
+ print_verbose("Building temporary manifest...");
String manifest_text =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
@@ -1395,7 +1406,7 @@ void EditorExportPlatformAndroid::_fix_resources(const Ref<EditorExportPreset> &
Vector<String> string_table;
String package_name = p_preset->get("package/name");
- Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
+ Dictionary appnames = GLOBAL_GET("application/config/name_localized");
for (uint32_t i = 0; i < string_count; i++) {
uint32_t offset = decode_uint32(&r_manifest[string_table_begins + i * 4]);
@@ -1505,9 +1516,9 @@ void EditorExportPlatformAndroid::_process_launcher_icons(const String &p_file_n
}
String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
- bool scale_splash = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
- bool apply_filter = ProjectSettings::get_singleton()->get("application/boot_splash/use_filter");
- String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ bool scale_splash = GLOBAL_GET("application/boot_splash/fullsize");
+ bool apply_filter = GLOBAL_GET("application/boot_splash/use_filter");
+ String project_splash_path = GLOBAL_GET("application/boot_splash/image");
if (!project_splash_path.is_empty()) {
splash_image.instantiate();
@@ -1528,7 +1539,7 @@ String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, R
}
if (scale_splash) {
- Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
int width, height;
if (screen_size.width > screen_size.height) {
// scale horizontally
@@ -1559,7 +1570,7 @@ String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, R
}
void EditorExportPlatformAndroid::load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) {
- String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
+ String project_icon_path = GLOBAL_GET("application/config/icon");
icon.instantiate();
foreground.instantiate();
@@ -1656,11 +1667,11 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
}
}
-Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExportPreset> &p_preset) {
- Vector<String> abis = get_abis();
- Vector<String> enabled_abis;
+Vector<EditorExportPlatformAndroid::ABI> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExportPreset> &p_preset) {
+ Vector<ABI> abis = get_abis();
+ Vector<ABI> enabled_abis;
for (int i = 0; i < abis.size(); ++i) {
- bool is_enabled = p_preset->get("architectures/" + abis[i]);
+ bool is_enabled = p_preset->get("architectures/" + abis[i].abi);
if (is_enabled) {
enabled_abis.push_back(abis[i]);
}
@@ -1671,9 +1682,10 @@ Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExp
void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
r_features->push_back("etc2");
- Vector<String> abis = get_enabled_abis(p_preset);
+ Vector<ABI> abis = get_enabled_abis(p_preset);
for (int i = 0; i < abis.size(); ++i) {
- r_features->push_back(abis[i]);
+ r_features->push_back(abis[i].arch);
+ r_features->push_back(abis[i].abi);
}
}
@@ -1697,9 +1709,9 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
// Android supports multiple architectures in an app bundle, so
// we expose each option as a checkbox in the export dialog.
- const Vector<String> abis = get_abis();
+ const Vector<ABI> abis = get_abis();
for (int i = 0; i < abis.size(); ++i) {
- const String abi = abis[i];
+ const String abi = abis[i].abi;
// All Android devices supporting Vulkan run 64-bit Android,
// so there is usually no point in exporting for 32-bit Android.
const bool is_default = abi == "arm64-v8a";
@@ -1920,7 +1932,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
print_verbose(output);
if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
- int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
+ int dbg_port = EDITOR_GET("network/debug/remote_port");
args.clear();
args.push_back("-s");
args.push_back(devices[p_device].id);
@@ -1935,7 +1947,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
}
if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) {
- int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port");
+ int fs_port = EDITOR_GET("filesystem/file_server/port");
args.clear();
args.push_back("-s");
@@ -1965,7 +1977,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
args.push_back("shell");
args.push_back("am");
args.push_back("start");
- if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].api_level >= 17) { // Multi-user introduced in Android 17
+ if ((bool)EDITOR_GET("export/android/force_system_user") && devices[p_device].api_level >= 17) { // Multi-user introduced in Android 17
args.push_back("--user");
args.push_back("0");
}
@@ -1995,7 +2007,7 @@ String EditorExportPlatformAndroid::get_adb_path() {
if (OS::get_singleton()->get_name() == "Windows") {
exe_ext = ".exe";
}
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ String sdk_path = EDITOR_GET("export/android/android_sdk_path");
return sdk_path.path_join("platform-tools/adb" + exe_ext);
}
@@ -2005,7 +2017,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
exe_ext = ".bat";
}
String apksigner_command_name = "apksigner" + exe_ext;
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ String sdk_path = EDITOR_GET("export/android/android_sdk_path");
String apksigner_path = "";
Error errn;
@@ -2099,7 +2111,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
}
if (!FileAccess::exists(dk)) {
- dk = EditorSettings::get_singleton()->get("export/android/debug_keystore");
+ dk = EDITOR_GET("export/android/debug_keystore");
if (!FileAccess::exists(dk)) {
valid = false;
err += TTR("Debug keystore not configured in the Editor Settings nor in the preset.") + "\n";
@@ -2120,7 +2132,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
err += TTR("Release keystore incorrectly configured in the export preset.") + "\n";
}
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ String sdk_path = EDITOR_GET("export/android/android_sdk_path");
if (sdk_path.is_empty()) {
err += TTR("A valid Android SDK path is required in Editor Settings.") + "\n";
valid = false;
@@ -2394,9 +2406,9 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
user = p_preset->get("keystore/debug_user");
if (keystore.is_empty()) {
- keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore");
- password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass");
- user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
+ keystore = EDITOR_GET("export/android/debug_keystore");
+ password = EDITOR_GET("export/android/debug_keystore_pass");
+ user = EDITOR_GET("export/android/debug_keystore_user");
}
if (ep.step(vformat(TTR("Signing debug %s..."), export_label), 104)) {
@@ -2479,7 +2491,7 @@ void EditorExportPlatformAndroid::_clear_assets_directory() {
// Clear the APK assets directory
if (da_res->dir_exists(APK_ASSETS_DIRECTORY)) {
- print_verbose("Clearing APK assets directory..");
+ print_verbose("Clearing APK assets directory...");
Ref<DirAccess> da_assets = DirAccess::open(APK_ASSETS_DIRECTORY);
da_assets->erase_contents_recursive();
da_res->remove(APK_ASSETS_DIRECTORY);
@@ -2487,7 +2499,7 @@ void EditorExportPlatformAndroid::_clear_assets_directory() {
// Clear the AAB assets directory
if (da_res->dir_exists(AAB_ASSETS_DIRECTORY)) {
- print_verbose("Clearing AAB assets directory..");
+ print_verbose("Clearing AAB assets directory...");
Ref<DirAccess> da_assets = DirAccess::open(AAB_ASSETS_DIRECTORY);
da_assets->erase_contents_recursive();
da_res->remove(AAB_ASSETS_DIRECTORY);
@@ -2516,13 +2528,24 @@ void EditorExportPlatformAndroid::_remove_copied_libs() {
da->remove(GDNATIVE_LIBS_PATH);
}
-String EditorExportPlatformAndroid::join_list(List<String> parts, const String &separator) const {
+String EditorExportPlatformAndroid::join_list(const List<String> &p_parts, const String &p_separator) {
+ String ret;
+ for (int i = 0; i < p_parts.size(); ++i) {
+ if (i > 0) {
+ ret += p_separator;
+ }
+ ret += p_parts[i];
+ }
+ return ret;
+}
+
+String EditorExportPlatformAndroid::join_abis(const Vector<EditorExportPlatformAndroid::ABI> &p_parts, const String &p_separator, bool p_use_arch) {
String ret;
- for (int i = 0; i < parts.size(); ++i) {
+ for (int i = 0; i < p_parts.size(); ++i) {
if (i > 0) {
- ret += separator;
+ ret += p_separator;
}
- ret += parts[i];
+ ret += (p_use_arch) ? p_parts[i].arch : p_parts[i].abi;
}
return ret;
}
@@ -2544,7 +2567,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
bool use_custom_build = bool(p_preset->get("custom_build/use_custom_build"));
bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG);
bool apk_expansion = p_preset->get("apk_expansion/enable");
- Vector<String> enabled_abis = get_enabled_abis(p_preset);
+ Vector<ABI> enabled_abis = get_enabled_abis(p_preset);
print_verbose("Exporting for Android...");
print_verbose("- debug build: " + bool_to_string(p_debug));
@@ -2553,7 +2576,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
print_verbose("- sign build: " + bool_to_string(should_sign));
print_verbose("- custom build enabled: " + bool_to_string(use_custom_build));
print_verbose("- apk expansion enabled: " + bool_to_string(apk_expansion));
- print_verbose("- enabled abis: " + String(",").join(enabled_abis));
+ print_verbose("- enabled abis: " + join_abis(enabled_abis, ",", false));
print_verbose("- export filter: " + itos(p_preset->get_export_filter()));
print_verbose("- include filter: " + p_preset->get_include_filter());
print_verbose("- exclude filter: " + p_preset->get_exclude_filter());
@@ -2592,10 +2615,10 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
}
if (use_custom_build) {
- print_verbose("Starting custom build..");
+ print_verbose("Starting custom build...");
//test that installed build version is alright
{
- print_verbose("Checking build version..");
+ print_verbose("Checking build version...");
Ref<FileAccess> f = FileAccess::open("res://android/.build_version", FileAccess::READ);
if (f.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
@@ -2628,7 +2651,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
_clear_assets_directory();
_remove_copied_libs();
if (!apk_expansion) {
- print_verbose("Exporting project files..");
+ print_verbose("Exporting project files...");
CustomExportData user_data;
user_data.assets_directory = assets_directory;
user_data.debug = p_debug;
@@ -2642,14 +2665,14 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
fa->store_string(JSON::stringify(user_data.libs, "\t"));
}
} else {
- print_verbose("Saving apk expansion file..");
+ print_verbose("Saving apk expansion file...");
err = save_apk_expansion_file(p_preset, p_debug, p_path);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not write expansion package file!"));
return err;
}
}
- print_verbose("Storing command line flags..");
+ print_verbose("Storing command line flags...");
store_file_at_path(assets_directory + "/_cl_", command_line_flags);
print_verbose("Updating ANDROID_HOME environment to " + sdk_path);
@@ -2676,7 +2699,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (!target_sdk_version.is_valid_int()) {
target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION);
}
- String enabled_abi_string = String("|").join(enabled_abis);
+ String enabled_abi_string = join_abis(enabled_abis, "|", false);
String sign_flag = should_sign ? "true" : "false";
String zipalign_flag = "true";
@@ -2728,9 +2751,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String debug_user = p_preset->get("keystore/debug_user");
if (debug_keystore.is_empty()) {
- debug_keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore");
- debug_password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass");
- debug_user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
+ debug_keystore = EDITOR_GET("export/android/debug_keystore");
+ debug_password = EDITOR_GET("export/android/debug_keystore_pass");
+ debug_user = EDITOR_GET("export/android/debug_keystore_user");
}
if (debug_keystore.is_relative_path()) {
debug_keystore = OS::get_singleton()->get_resource_dir().path_join(debug_keystore).simplify_path();
@@ -2802,7 +2825,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
return OK;
}
// This is the start of the Legacy build system
- print_verbose("Starting legacy build system..");
+ print_verbose("Starting legacy build system...");
if (p_debug) {
src_apk = p_preset->get("custom_template/debug");
} else {
@@ -2861,7 +2884,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
- Vector<String> invalid_abis(enabled_abis);
+ Vector<ABI> invalid_abis(enabled_abis);
while (ret == UNZ_OK) {
//get filename
unz_file_info info;
@@ -2924,7 +2947,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (file.ends_with(".so")) {
bool enabled = false;
for (int i = 0; i < enabled_abis.size(); ++i) {
- if (file.begins_with("lib/" + enabled_abis[i] + "/")) {
+ if (file.begins_with("lib/" + enabled_abis[i].abi + "/")) {
invalid_abis.erase(enabled_abis[i]);
enabled = true;
break;
@@ -2966,8 +2989,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
}
if (!invalid_abis.is_empty()) {
- String unsupported_arch = String(", ").join(invalid_abis);
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Missing libraries in the export template for the selected architectures: %s. Please build a template with all required libraries, or uncheck the missing architectures in the export preset."), unsupported_arch));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Missing libraries in the export template for the selected architectures: %s. Please build a template with all required libraries, or uncheck the missing architectures in the export preset."), join_abis(invalid_abis, ", ", false)));
CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 46012bd46c..c8fcb761fe 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -99,7 +99,22 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
static zip_fileinfo get_zip_fileinfo();
- static Vector<String> get_abis();
+ struct ABI {
+ String abi;
+ String arch;
+
+ bool operator==(const ABI &p_a) const {
+ return p_a.abi == abi;
+ }
+
+ ABI(const String &p_abi, const String &p_arch) {
+ abi = p_abi;
+ arch = p_arch;
+ }
+ ABI() {}
+ };
+
+ static Vector<ABI> get_abis();
/// List the gdap files in the directory specified by the p_path parameter.
static Vector<String> list_gdap_files(const String &p_path);
@@ -152,7 +167,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
const Ref<Image> &foreground,
const Ref<Image> &background);
- static Vector<String> get_enabled_abis(const Ref<EditorExportPreset> &p_preset);
+ static Vector<ABI> get_enabled_abis(const Ref<EditorExportPreset> &p_preset);
public:
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
@@ -228,7 +243,8 @@ public:
void _remove_copied_libs();
- String join_list(List<String> parts, const String &separator) const;
+ static String join_list(const List<String> &p_parts, const String &p_separator);
+ static String join_abis(const Vector<ABI> &p_parts, const String &p_separator, bool p_use_arch);
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index 2f53942f76..8d016d3fac 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -158,7 +158,7 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset
return ERR_CANT_OPEN;
}
da->list_dir_begin();
- Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
+ Dictionary appnames = GLOBAL_GET("application/config/name_localized");
while (true) {
String file = da->get_next();
if (file.is_empty()) {
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 0346625e4b..e1d9dc4cde 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -1,10 +1,10 @@
ext.versions = [
- androidGradlePlugin: '7.0.3',
+ androidGradlePlugin: '7.2.1',
compileSdk : 32,
- minSdk : 19, // Also update 'platform/android/java/lib/AndroidManifest.xml#minSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION'
- targetSdk : 32, // Also update 'platform/android/java/lib/AndroidManifest.xml#targetSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
+ minSdk : 19, // Also update 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION'
+ targetSdk : 32, // Also update 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
buildTools : '32.0.0',
- kotlinVersion : '1.6.21',
+ kotlinVersion : '1.7.0',
fragmentVersion : '1.3.6',
nexusPublishVersion: '1.1.0',
javaVersion : 11,
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
index 489a81fc1a..46a334ef38 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
@@ -37,10 +37,12 @@ import android.os.Build
import android.os.Bundle
import android.os.Debug
import android.os.Environment
+import android.util.Log
import android.widget.Toast
import androidx.window.layout.WindowMetricsCalculator
import org.godotengine.godot.FullScreenGodotApp
import org.godotengine.godot.utils.PermissionsUtil
+import org.godotengine.godot.utils.ProcessPhoenix
import java.util.*
import kotlin.math.min
@@ -56,12 +58,17 @@ import kotlin.math.min
open class GodotEditor : FullScreenGodotApp() {
companion object {
+ private val TAG = GodotEditor::class.java.simpleName
+
private const val WAIT_FOR_DEBUGGER = false
private const val COMMAND_LINE_PARAMS = "command_line_params"
private const val EDITOR_ARG = "--editor"
+ private const val EDITOR_ARG_SHORT = "-e"
+
private const val PROJECT_MANAGER_ARG = "--project-manager"
+ private const val PROJECT_MANAGER_ARG_SHORT = "-p"
}
private val commandLineParams = ArrayList<String>()
@@ -105,13 +112,13 @@ open class GodotEditor : FullScreenGodotApp() {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && (isInMultiWindowMode || isLargeScreen)
for (arg in args) {
- if (EDITOR_ARG == arg) {
+ if (EDITOR_ARG == arg || EDITOR_ARG_SHORT == arg) {
targetClass = GodotEditor::class.java
launchAdjacent = false
break
}
- if (PROJECT_MANAGER_ARG == arg) {
+ if (PROJECT_MANAGER_ARG == arg || PROJECT_MANAGER_ARG_SHORT == arg) {
targetClass = GodotProjectManager::class.java
launchAdjacent = false
break
@@ -125,7 +132,13 @@ open class GodotEditor : FullScreenGodotApp() {
if (launchAdjacent) {
newInstance.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT)
}
- startActivity(newInstance)
+ if (targetClass == javaClass) {
+ Log.d(TAG, "Restarting $targetClass")
+ ProcessPhoenix.triggerRebirth(this, newInstance)
+ } else {
+ Log.d(TAG, "Starting $targetClass")
+ startActivity(newInstance)
+ }
}
// Get the screen's density scale
diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
index ffed3a254e..41dfb87909 100644
--- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/platform/android/java/lib/AndroidManifest.xml b/platform/android/java/lib/AndroidManifest.xml
index 79b5aadf2a..1f77e2fc34 100644
--- a/platform/android/java/lib/AndroidManifest.xml
+++ b/platform/android/java/lib/AndroidManifest.xml
@@ -4,9 +4,6 @@
android:versionCode="1"
android:versionName="1.0">
- <!-- Should match the mindSdk and targetSdk values in platform/android/java/app/config.gradle -->
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="32" />
-
<application>
<!-- Records the version of the Godot library -->
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index c9e2a5d7d2..841656a240 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -176,11 +176,10 @@ android {
}
}
- // TODO: Enable when issues with AGP 7.1+ are resolved (https://github.com/GodotVR/godot_openxr/issues/187).
-// publishing {
-// singleVariant("templateRelease") {
-// withSourcesJar()
-// withJavadocJar()
-// }
-// }
+ publishing {
+ singleVariant("templateRelease") {
+ withSourcesJar()
+ withJavadocJar()
+ }
+ }
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 92e5e59496..a002a37ab9 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -299,7 +299,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onRegisterPluginWithGodotNative();
}
- setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
+ setKeepScreenOn(Boolean.parseBoolean(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
});
// Include the returned non-null views in the Godot view hierarchy.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 26aad867b1..33896ecb95 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -110,7 +110,7 @@ public class GodotLib {
/**
* Forward touch events.
*/
- public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions);
+ public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions, boolean doubleTap);
/**
* Dispatch mouse events
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index 7925b54fc4..804dbaf165 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -127,7 +127,9 @@ public class GodotEditText extends EditText {
edit.setText("");
edit.append(text);
if (msg.arg2 != -1) {
- edit.setSelection(msg.arg1, msg.arg2);
+ int selectionStart = Math.min(msg.arg1, edit.length());
+ int selectionEnd = Math.min(msg.arg2, edit.length());
+ edit.setSelection(selectionStart, selectionEnd);
edit.mInputWrapper.setSelection(true);
} else {
edit.mInputWrapper.setSelection(false);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
index 9715c31fc1..cde8d7cdae 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -55,18 +55,15 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
*/
var panningAndScalingEnabled = false
- private var doubleTapInProgress = false
+ private var nextDownIsDoubleTap = false
private var dragInProgress = false
private var scaleInProgress = false
private var contextClickInProgress = false
private var pointerCaptureInProgress = false
override fun onDown(event: MotionEvent): Boolean {
- // Don't send / register a down event while we're in the middle of a double-tap
- if (!doubleTapInProgress) {
- // Send the down event
- GodotInputHandler.handleMotionEvent(event)
- }
+ GodotInputHandler.handleMotionEvent(event.source, MotionEvent.ACTION_DOWN, event.buttonState, event.x, event.y, nextDownIsDoubleTap)
+ nextDownIsDoubleTap = false
return true
}
@@ -80,7 +77,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
private fun contextClickRouter(event: MotionEvent) {
- if (scaleInProgress) {
+ if (scaleInProgress || nextDownIsDoubleTap) {
return
}
@@ -137,40 +134,24 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
private fun onActionUp(event: MotionEvent): Boolean {
+ if (event.actionMasked == MotionEvent.ACTION_CANCEL && pointerCaptureInProgress) {
+ // Don't dispatch the ACTION_CANCEL while a capture is in progress
+ return true
+ }
+
val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
} else {
false
}
- when {
- pointerCaptureInProgress -> {
- return if (event.actionMasked == MotionEvent.ACTION_CANCEL) {
- // Don't dispatch the ACTION_CANCEL while a capture is in progress
- true
- } else {
- GodotInputHandler.handleMouseEvent(
- MotionEvent.ACTION_UP,
- event.buttonState,
- event.x,
- event.y,
- 0f,
- 0f,
- false,
- sourceMouseRelative
- )
- pointerCaptureInProgress = false
- true
- }
- }
- dragInProgress -> {
- GodotInputHandler.handleMotionEvent(event)
- dragInProgress = false
- return true
- }
- contextClickInProgress -> {
+
+ if (pointerCaptureInProgress || dragInProgress || contextClickInProgress) {
+ if (contextClickInProgress || GodotInputHandler.isMouseEvent(event)) {
+ // This may be an ACTION_BUTTON_RELEASE event which we don't handle,
+ // so we convert it to an ACTION_UP event.
GodotInputHandler.handleMouseEvent(
- event.actionMasked,
- 0,
+ MotionEvent.ACTION_UP,
+ event.buttonState,
event.x,
event.y,
0f,
@@ -178,11 +159,16 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
false,
sourceMouseRelative
)
- contextClickInProgress = false
- return true
+ } else {
+ GodotInputHandler.handleTouchEvent(event)
}
- else -> return false
+ pointerCaptureInProgress = false
+ dragInProgress = false
+ contextClickInProgress = false
+ return true
}
+
+ return false
}
private fun onActionMove(event: MotionEvent): Boolean {
@@ -209,24 +195,14 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
override fun onDoubleTapEvent(event: MotionEvent): Boolean {
if (event.actionMasked == MotionEvent.ACTION_UP) {
- doubleTapInProgress = false
+ nextDownIsDoubleTap = false
+ GodotInputHandler.handleMotionEvent(event)
}
return true
}
override fun onDoubleTap(event: MotionEvent): Boolean {
- doubleTapInProgress = true
- val x = event.x
- val y = event.y
- val buttonMask =
- if (GodotInputHandler.isMouseEvent(event)) {
- event.buttonState
- } else {
- MotionEvent.BUTTON_PRIMARY
- }
- GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_DOWN, buttonMask, x, y, true)
- GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, 0, x, y, false)
-
+ nextDownIsDoubleTap = true
return true
}
@@ -255,7 +231,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
val x = terminusEvent.x
val y = terminusEvent.y
- if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled) {
+ if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress) {
GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
} else {
GodotInputHandler.handleMotionEvent(terminusEvent)
@@ -264,7 +240,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
override fun onScale(detector: ScaleGestureDetector?): Boolean {
- if (detector == null || !panningAndScalingEnabled) {
+ if (detector == null || !panningAndScalingEnabled || pointerCaptureInProgress) {
return false
}
GodotLib.magnify(
@@ -276,7 +252,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
- if (detector == null || !panningAndScalingEnabled) {
+ if (detector == null || !panningAndScalingEnabled || pointerCaptureInProgress) {
return false
}
scaleInProgress = true
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index 03cb8034fa..2f26497cc8 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -245,7 +245,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
return true;
}
- } else if (isMouseEvent(event)) {
+ } else {
return handleMouseEvent(event);
}
@@ -438,15 +438,19 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) {
- return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0);
+ return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, false);
+ }
+
+ static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, boolean doubleTap) {
+ return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0, doubleTap);
}
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY) {
+ static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleTap) {
if (isMouseEvent(eventSource)) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, false, false);
+ return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleTap, false);
}
- return handleTouchEvent(eventAction, x, y);
+ return handleTouchEvent(eventAction, x, y, doubleTap);
}
static boolean handleMouseEvent(final MotionEvent event) {
@@ -468,11 +472,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false);
}
- static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick, false);
- }
-
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
+ // We don't handle ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE events as they typically
+ // follow ACTION_DOWN and ACTION_UP events. As such, handling them would result in duplicate
+ // stream of events to the engine.
switch (eventAction) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
@@ -508,14 +511,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
final int action = event.getActionMasked();
final int actionPointerId = event.getPointerId(event.getActionIndex());
- return handleTouchEvent(action, actionPointerId, pointerCount, positions);
+ return handleTouchEvent(action, actionPointerId, pointerCount, positions, false);
}
- static boolean handleTouchEvent(int eventAction, float x, float y) {
- return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y });
+ static boolean handleTouchEvent(int eventAction, float x, float y, boolean doubleTap) {
+ return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y }, doubleTap);
}
- static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions) {
+ static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions, boolean doubleTap) {
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
@@ -523,7 +526,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
- GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions);
+ GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions, doubleTap);
return true;
}
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 04b69d5b86..c2c25601d7 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -71,6 +71,39 @@ static Vector3 gravity;
static Vector3 magnetometer;
static Vector3 gyroscope;
+static void _terminate(JNIEnv *env, bool p_restart = false) {
+ step.set(-1); // Ensure no further steps are attempted and no further events are sent
+
+ // lets cleanup
+ if (java_class_wrapper) {
+ memdelete(java_class_wrapper);
+ }
+ if (input_handler) {
+ delete input_handler;
+ }
+ // Whether restarting is handled by 'Main::cleanup()'
+ bool restart_on_cleanup = false;
+ if (os_android) {
+ restart_on_cleanup = os_android->is_restart_on_exit_set();
+ os_android->main_loop_end();
+ Main::cleanup();
+ delete os_android;
+ }
+ if (godot_io_java) {
+ delete godot_io_java;
+ }
+ if (godot_java) {
+ if (!restart_on_cleanup) {
+ if (p_restart) {
+ godot_java->restart(env);
+ } else {
+ godot_java->force_quit(env);
+ }
+ }
+ delete godot_java;
+ }
+}
+
extern "C" {
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height) {
@@ -104,23 +137,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz) {
- // lets cleanup
- if (java_class_wrapper) {
- memdelete(java_class_wrapper);
- }
- if (godot_io_java) {
- delete godot_io_java;
- }
- if (godot_java) {
- delete godot_java;
- }
- if (input_handler) {
- delete input_handler;
- }
- if (os_android) {
- os_android->main_loop_end();
- delete os_android;
- }
+ _terminate(env, false);
}
JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) {
@@ -196,9 +213,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
}
} else {
// Rendering context recreated because it was lost; restart app to let it reload everything
- step.set(-1); // Ensure no further steps are attempted and no further events are sent
- os_android->main_loop_end();
- godot_java->restart(env);
+ _terminate(env, true);
}
}
}
@@ -249,7 +264,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env,
bool should_swap_buffers = false;
if (os_android->main_loop_iterate(&should_swap_buffers)) {
- godot_java->force_quit(env);
+ _terminate(env, false);
}
return should_swap_buffers;
@@ -265,7 +280,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JN
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position, jboolean p_double_tap) {
if (step.get() <= 0) {
return;
}
@@ -280,7 +295,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JN
points.push_back(tp);
}
- input_handler->process_touch_event(ev, pointer, points);
+ input_handler->process_touch_event(ev, pointer, points, p_double_tap);
}
// Called on the UI thread
@@ -409,7 +424,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env,
JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path) {
String js = jstring_to_string(path, env);
- return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data());
+ return env->NewStringUTF(GLOBAL_GET(js).operator String().utf8().get_data());
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 09fed15690..f3f2646bfb 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -46,7 +46,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env,
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jboolean p_double_tap);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed);
diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp
index 762840a4b1..378a467772 100644
--- a/platform/android/java_godot_view_wrapper.cpp
+++ b/platform/android/java_godot_view_wrapper.cpp
@@ -68,7 +68,7 @@ void GodotJavaViewWrapper::request_pointer_capture() {
}
void GodotJavaViewWrapper::release_pointer_capture() {
- if (_request_pointer_capture != nullptr) {
+ if (_release_pointer_capture != nullptr) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL(env);
diff --git a/platform/android/jni_utils.cpp b/platform/android/jni_utils.cpp
index d46b4f39de..2b0ee50570 100644
--- a/platform/android/jni_utils.cpp
+++ b/platform/android/jni_utils.cpp
@@ -265,33 +265,33 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
if (name == "[D") {
jdoubleArray arr = (jdoubleArray)obj;
int fCount = env->GetArrayLength(arr);
- PackedFloat32Array sarr;
- sarr.resize(fCount);
+ PackedFloat64Array packed_array;
+ packed_array.resize(fCount);
- real_t *w = sarr.ptrw();
+ double *w = packed_array.ptrw();
for (int i = 0; i < fCount; i++) {
double n;
env->GetDoubleArrayRegion(arr, i, 1, &n);
w[i] = n;
}
- return sarr;
+ return packed_array;
}
if (name == "[F") {
jfloatArray arr = (jfloatArray)obj;
int fCount = env->GetArrayLength(arr);
- PackedFloat32Array sarr;
- sarr.resize(fCount);
+ PackedFloat32Array packed_array;
+ packed_array.resize(fCount);
- real_t *w = sarr.ptrw();
+ float *w = packed_array.ptrw();
for (int i = 0; i < fCount; i++) {
float n;
env->GetFloatArrayRegion(arr, i, 1, &n);
w[i] = n;
}
- return sarr;
+ return packed_array;
}
if (name == "[Ljava.lang.Object;") {
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 4469c7a0f7..97fa90b1d2 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -162,11 +162,16 @@ Vector<String> OS_Android::get_granted_permissions() const {
}
Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
- p_library_handle = dlopen(p_path.utf8().get_data(), RTLD_NOW);
+ String path = p_path;
+ if (!FileAccess::exists(path)) {
+ path = p_path.get_file();
+ }
+
+ p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
if (r_resolved_path != nullptr) {
- *r_resolved_path = p_path;
+ *r_resolved_path = path;
}
return OK;
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index 7a39e2003d..5a7123b833 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -135,9 +135,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
}
// Retrieve the current list of gdnative libraries.
- Array singletons = Array();
+ Array singletons;
if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
- singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ singletons = GLOBAL_GET("gdnative/singletons");
}
// Insert the libraries provided by the plugin
diff --git a/platform/android/vulkan/vulkan_context_android.cpp b/platform/android/vulkan/vulkan_context_android.cpp
index c802c9840b..948292c3af 100644
--- a/platform/android/vulkan/vulkan_context_android.cpp
+++ b/platform/android/vulkan/vulkan_context_android.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef VULKAN_ENABLED
+
#include "vulkan_context_android.h"
#ifdef USE_VOLK
@@ -63,3 +65,5 @@ bool VulkanContextAndroid::_use_validation_layers() {
// On Android, we use validation layers automatically if they were explicitly linked with the app.
return count > 0;
}
+
+#endif // VULKAN_ENABLED
diff --git a/platform/android/vulkan/vulkan_context_android.h b/platform/android/vulkan/vulkan_context_android.h
index ca8182e9cd..fe9a033e1c 100644
--- a/platform/android/vulkan/vulkan_context_android.h
+++ b/platform/android/vulkan/vulkan_context_android.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_ANDROID_H
#define VULKAN_CONTEXT_ANDROID_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
struct ANativeWindow;
@@ -48,4 +50,6 @@ protected:
bool _use_validation_layers() override;
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_ANDROID_H
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index f3624f24ab..447f919139 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -40,7 +40,6 @@
#include "vulkan_context_ios.h"
-#import <QuartzCore/CAMetalLayer.h>
#ifdef USE_VOLK
#include <volk.h>
#else
@@ -48,6 +47,9 @@
#endif
#endif
+#import <Foundation/Foundation.h>
+#import <QuartzCore/CAMetalLayer.h>
+
class DisplayServerIOS : public DisplayServer {
GDCLASS(DisplayServerIOS, DisplayServer)
@@ -73,7 +75,7 @@ class DisplayServerIOS : public DisplayServer {
void perform_event(const Ref<InputEvent> &p_event);
- DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerIOS();
public:
@@ -82,7 +84,7 @@ public:
static DisplayServerIOS *get_singleton();
static void register_ios_driver();
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
// MARK: - Events
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index d3a0f38463..6793b40dd4 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -41,7 +41,6 @@
#include "tts_ios.h"
#import "view_controller.h"
-#import <Foundation/Foundation.h>
#import <sys/utsname.h>
static const float kDisplayServerIOSAcceleration = 1.f;
@@ -50,7 +49,7 @@ DisplayServerIOS *DisplayServerIOS::get_singleton() {
return (DisplayServerIOS *)DisplayServer::get_singleton();
}
-DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
rendering_driver = p_rendering_driver;
// Init TTS
@@ -152,8 +151,8 @@ DisplayServerIOS::~DisplayServerIOS() {
#endif
}
-DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
+ return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
}
Vector<String> DisplayServerIOS::get_rendering_drivers_func() {
@@ -228,19 +227,20 @@ void DisplayServerIOS::_window_callback(const Callable &p_callable, const Varian
// MARK: Touches
void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) {
- if (!GLOBAL_DEF("debug/disable_touch", false)) {
+ if (!GLOBAL_GET("debug/disable_touch")) {
Ref<InputEventScreenTouch> ev;
ev.instantiate();
ev->set_index(p_idx);
ev->set_pressed(p_pressed);
ev->set_position(Vector2(p_x, p_y));
+ ev->set_double_tap(p_double_click);
perform_event(ev);
}
}
void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) {
- if (!GLOBAL_DEF("debug/disable_touch", false)) {
+ if (!GLOBAL_GET("debug/disable_touch")) {
Ref<InputEventScreenDrag> ev;
ev.instantiate();
ev->set_index(p_idx);
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 83b2012d3e..33f1071077 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -49,6 +49,46 @@ Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_ge
return archs;
}
+struct IconInfo {
+ const char *preset_key;
+ const char *idiom;
+ const char *export_name;
+ const char *actual_size_side;
+ const char *scale;
+ const char *unscaled_size;
+ const bool force_opaque;
+};
+
+static const IconInfo icon_infos[] = {
+ // Home screen on iPhone
+ { PNAME("icons/iphone_120x120"), "iphone", "Icon-120.png", "120", "2x", "60x60", false },
+ { PNAME("icons/iphone_120x120"), "iphone", "Icon-120.png", "120", "3x", "40x40", false },
+ { PNAME("icons/iphone_180x180"), "iphone", "Icon-180.png", "180", "3x", "60x60", false },
+
+ // Home screen on iPad
+ { PNAME("icons/ipad_76x76"), "ipad", "Icon-76.png", "76", "1x", "76x76", false },
+ { PNAME("icons/ipad_152x152"), "ipad", "Icon-152.png", "152", "2x", "76x76", false },
+ { PNAME("icons/ipad_167x167"), "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false },
+
+ // App Store
+ { PNAME("icons/app_store_1024x1024"), "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true },
+
+ // Spotlight
+ { PNAME("icons/spotlight_40x40"), "ipad", "Icon-40.png", "40", "1x", "40x40", false },
+ { PNAME("icons/spotlight_80x80"), "iphone", "Icon-80.png", "80", "2x", "40x40", false },
+ { PNAME("icons/spotlight_80x80"), "ipad", "Icon-80.png", "80", "2x", "40x40", false },
+
+ // Settings
+ { PNAME("icons/settings_58x58"), "iphone", "Icon-58.png", "58", "2x", "29x29", false },
+ { PNAME("icons/settings_58x58"), "ipad", "Icon-58.png", "58", "2x", "29x29", false },
+ { PNAME("icons/settings_87x87"), "iphone", "Icon-87.png", "87", "3x", "29x29", false },
+
+ // Notification
+ { PNAME("icons/notification_40x40"), "iphone", "Icon-40.png", "40", "2x", "20x20", false },
+ { PNAME("icons/notification_40x40"), "ipad", "Icon-40.png", "40", "2x", "20x20", false },
+ { PNAME("icons/notification_60x60"), "iphone", "Icon-60.png", "60", "3x", "20x20", false }
+};
+
struct LoadingScreenInfo {
const char *preset_key;
const char *export_name;
@@ -97,6 +137,9 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/launch_screens_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
+
Vector<PluginConfigIOS> found_plugins = get_plugins();
for (int i = 0; i < found_plugins.size(); i++) {
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("plugins"), found_plugins[i].name)), false));
@@ -139,18 +182,13 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photolibrary_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone/iPod Touch with Retina display
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone with Retina HD display
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad with Retina display
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad Pro
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // App Store
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight on devices with Retina display
-
+ HashSet<String> used_names;
+ for (uint64_t i = 0; i < sizeof(icon_infos) / sizeof(icon_infos[0]); ++i) {
+ if (!used_names.has(icon_infos[i].preset_key)) {
+ used_names.insert(icon_infos[i].preset_key);
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, icon_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
+ }
+ }
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
@@ -358,8 +396,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
switch (image_scale_mode) {
case 0: {
- String logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
- bool is_on = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ String logo_path = GLOBAL_GET("application/boot_splash/image");
+ bool is_on = GLOBAL_GET("application/boot_splash/fullsize");
// If custom logo is not specified, Godot does not scale default one, so we should do the same.
value = (is_on && logo_path.length() > 0) ? "scaleAspectFit" : "center";
} break;
@@ -371,7 +409,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n";
} else if (lines[i].find("$launch_screen_background_color") != -1) {
bool use_custom = p_preset->get("storyboard/use_custom_bg_color");
- Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
+ Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : GLOBAL_GET("application/boot_splash/bg_color");
const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
Dictionary value_dictionary;
@@ -384,7 +422,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$launch_screen_background_color", value) + "\n";
} else if (lines[i].find("$pbx_locale_file_reference") != -1) {
String locale_files;
- Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
HashSet<String> languages;
for (const String &E : translations) {
@@ -403,7 +441,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$pbx_locale_file_reference", locale_files);
} else if (lines[i].find("$pbx_locale_build_reference") != -1) {
String locale_files;
- Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
HashSet<String> languages;
for (const String &E : translations) {
@@ -531,36 +569,6 @@ void EditorExportPlatformIOS::_blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p
}
}
-struct IconInfo {
- const char *preset_key;
- const char *idiom;
- const char *export_name;
- const char *actual_size_side;
- const char *scale;
- const char *unscaled_size;
- const bool force_opaque;
-};
-
-static const IconInfo icon_infos[] = {
- // Home screen on iPhone
- { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", false },
- { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", false },
- { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false },
-
- // Home screen on iPad
- { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", false },
- { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false },
- { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false },
-
- // App Store
- { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true },
-
- // Spotlight
- { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false },
- { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false },
- { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false }
-};
-
Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) {
String json_description = "{\"images\":[";
String sizes;
@@ -568,25 +576,31 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
Ref<DirAccess> da = DirAccess::open(p_iconset_dir);
ERR_FAIL_COND_V_MSG(da.is_null(), ERR_CANT_OPEN, "Cannot open directory '" + p_iconset_dir + "'.");
+ Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
+
for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
IconInfo info = icon_infos[i];
int side_size = String(info.actual_size_side).to_int();
String icon_path = p_preset->get(info.preset_key);
if (icon_path.length() == 0) {
// Resize main app icon
- icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
+ icon_path = GLOBAL_GET("application/config/icon");
Ref<Image> img = memnew(Image);
Error err = ImageLoader::load_image(icon_path, img);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path));
return ERR_UNCONFIGURED;
+ } else if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
+ img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
+ Ref<Image> new_img = Image::create_empty(side_size, side_size, false, Image::FORMAT_RGBA8);
+ new_img->fill(boot_bg_color);
+ _blend_and_rotate(new_img, img, false);
+ err = new_img->save_png(p_iconset_dir + info.export_name);
+ } else {
+ img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
+ err = img->save_png(p_iconset_dir + info.export_name);
}
- if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
- return ERR_UNCONFIGURED;
- }
- img->resize(side_size, side_size);
- err = img->save_png(p_iconset_dir + info.export_name);
if (err) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path));
return err;
@@ -598,14 +612,16 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path));
return ERR_UNCONFIGURED;
- }
- if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
- return ERR_UNCONFIGURED;
- }
- if (img->get_width() != side_size || img->get_height() != side_size) {
+ } else if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
+ img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
+ Ref<Image> new_img = Image::create_empty(side_size, side_size, false, Image::FORMAT_RGBA8);
+ new_img->fill(boot_bg_color);
+ _blend_and_rotate(new_img, img, false);
+ err = new_img->save_png(p_iconset_dir + info.export_name);
+ } else if (img->get_width() != side_size || img->get_height() != side_size) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s): '%s' has incorrect size %s and was automatically resized to %s.", info.preset_key, icon_path, img->get_size(), Vector2i(side_size, side_size)));
- img->resize(side_size, side_size);
+ img->resize(side_size, side_size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
err = img->save_png(p_iconset_dir + info.export_name);
} else {
err = da->copy(icon_path, p_iconset_dir + info.export_name);
@@ -650,7 +666,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
Ref<Image> image;
String image_path = p_dest_dir.path_join("splash@2x.png");
image.instantiate();
- Error err = image->load(custom_launch_image_2x);
+ Error err = ImageLoader::load_image(custom_launch_image_2x, image);
if (err) {
image.unref();
@@ -664,7 +680,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
image.unref();
image_path = p_dest_dir.path_join("splash@3x.png");
image.instantiate();
- err = image->load(custom_launch_image_3x);
+ err = ImageLoader::load_image(custom_launch_image_3x, image);
if (err) {
image.unref();
@@ -677,11 +693,11 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
} else {
Ref<Image> splash;
- const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ const String splash_path = GLOBAL_GET("application/boot_splash/image");
if (!splash_path.is_empty()) {
splash.instantiate();
- const Error err = splash->load(splash_path);
+ const Error err = ImageLoader::load_image(splash_path, splash);
if (err) {
splash.unref();
}
@@ -718,9 +734,9 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp
LoadingScreenInfo info = loading_screen_infos[i];
String loading_screen_file = p_preset->get(info.preset_key);
- Color boot_bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
- String boot_logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
- bool boot_logo_scale = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
+ String boot_logo_path = GLOBAL_GET("application/boot_splash/image");
+ bool boot_logo_scale = GLOBAL_GET("application/boot_splash/fullsize");
if (loading_screen_file.size() > 0) {
// Load custom loading screens, and resize if required.
@@ -735,9 +751,9 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp
float aspect_ratio = (float)img->get_width() / (float)img->get_height();
if (boot_logo_scale) {
if (info.height * aspect_ratio <= info.width) {
- img->resize(info.height * aspect_ratio, info.height);
+ img->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
} else {
- img->resize(info.width, info.width / aspect_ratio);
+ img->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
}
}
Ref<Image> new_img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8);
@@ -771,17 +787,17 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp
if (info.rotate) {
if (boot_logo_scale) {
if (info.width * aspect_ratio <= info.height) {
- img_bs->resize(info.width * aspect_ratio, info.width);
+ img_bs->resize(info.width * aspect_ratio, info.width, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
} else {
- img_bs->resize(info.height, info.height / aspect_ratio);
+ img_bs->resize(info.height, info.height / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
}
}
} else {
if (boot_logo_scale) {
if (info.height * aspect_ratio <= info.width) {
- img_bs->resize(info.height * aspect_ratio, info.height);
+ img_bs->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
} else {
- img_bs->resize(info.width, info.width / aspect_ratio);
+ img_bs->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
}
}
}
@@ -1494,8 +1510,8 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
print_line("Static framework: " + library_to_use);
String pkg_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ if (String(GLOBAL_GET("application/config/name")) != "") {
+ pkg_name = String(GLOBAL_GET("application/config/name"));
} else {
pkg_name = "Unnamed";
}
@@ -1644,12 +1660,12 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
return ERR_FILE_NOT_FOUND;
}
- Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
+ Dictionary appnames = GLOBAL_GET("application/config/name_localized");
Dictionary camera_usage_descriptions = p_preset->get("privacy/camera_usage_description_localized");
Dictionary microphone_usage_descriptions = p_preset->get("privacy/microphone_usage_description_localized");
Dictionary photolibrary_usage_descriptions = p_preset->get("privacy/photolibrary_usage_description_localized");
- Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
{
String fname = dest_dir + binary_name + "/en.lproj";
@@ -1657,7 +1673,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
f->store_line("/* Localized versions of Info.plist keys */");
f->store_line("");
- f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";");
+ f->store_line("CFBundleDisplayName = \"" + GLOBAL_GET("application/config/name").operator String() + "\";");
f->store_line("NSCameraUsageDescription = \"" + p_preset->get("privacy/camera_usage_description").operator String() + "\";");
f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String() + "\";");
f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photolibrary_usage_description").operator String() + "\";");
diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm
index ff90c05b1d..4537dc2985 100644
--- a/platform/ios/godot_view.mm
+++ b/platform/ios/godot_view.mm
@@ -30,6 +30,7 @@
#import "godot_view.h"
+#include "core/config/project_settings.h"
#include "core/os/keyboard.h"
#include "core/string/ustring.h"
#import "display_layer.h"
@@ -205,16 +206,16 @@ static const float earth_gravity = 9.80665;
if (self.useCADisplayLink) {
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)];
- // Approximate frame rate
- // assumes device refreshes at 60 fps
- int displayFPS = (NSInteger)(1.0 / self.renderingInterval);
-
- self.displayLink.preferredFramesPerSecond = displayFPS;
+ if (GLOBAL_GET("display/window/ios/allow_high_refresh_rate")) {
+ self.displayLink.preferredFramesPerSecond = 120;
+ } else {
+ self.displayLink.preferredFramesPerSecond = 60;
+ }
// Setup DisplayLink in main thread
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
} else {
- self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:self.renderingInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
+ self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / 60) target:self selector:@selector(drawView) userInfo:nil repeats:YES];
}
}
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index a674498620..b6b94d2f5e 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -396,7 +396,14 @@ void OS_IOS::vibrate_handheld(int p_duration_ms) {
}
bool OS_IOS::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "mobile";
+ if (p_feature == "system_fonts") {
+ return true;
+ }
+ if (p_feature == "mobile") {
+ return true;
+ }
+
+ return false;
}
void OS_IOS::on_focus_out() {
diff --git a/platform/ios/vulkan_context_ios.h b/platform/ios/vulkan_context_ios.h
index e9c09e087a..3849c8ba8a 100644
--- a/platform/ios/vulkan_context_ios.h
+++ b/platform/ios/vulkan_context_ios.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_IOS_H
#define VULKAN_CONTEXT_IOS_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
#import <UIKit/UIKit.h>
@@ -45,4 +47,6 @@ public:
~VulkanContextIOS();
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_IOS_H
diff --git a/platform/ios/vulkan_context_ios.mm b/platform/ios/vulkan_context_ios.mm
index 09cd369aa5..81b021e758 100644
--- a/platform/ios/vulkan_context_ios.mm
+++ b/platform/ios/vulkan_context_ios.mm
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef VULKAN_ENABLED
+
#include "vulkan_context_ios.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -57,3 +59,5 @@ Error VulkanContextIOS::window_create(DisplayServer::WindowID p_window_id, Displ
VulkanContextIOS::VulkanContextIOS() {}
VulkanContextIOS::~VulkanContextIOS() {}
+
+#endif // VULKAN_ENABLED
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
index 91d45627b9..fcd739cdc9 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -14,15 +14,7 @@ common_linuxbsd = [
]
if env["x11"]:
- common_linuxbsd += [
- "gl_manager_x11.cpp",
- "detect_prime_x11.cpp",
- "display_server_x11.cpp",
- "key_mapping_x11.cpp",
- ]
-
- if env["vulkan"]:
- common_linuxbsd.append("vulkan_context_x11.cpp")
+ common_linuxbsd += SConscript("x11/SCsub")
if env["speechd"]:
common_linuxbsd.append(["speechd-so_wrap.c", "tts_linux.cpp"])
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index ac69f3806b..004bcb8674 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -356,7 +356,6 @@ def configure(env: "Environment"):
if env["opengl3"]:
env.Append(CPPDEFINES=["GLES3_ENABLED"])
- env.ParseConfig("pkg-config gl --cflags --libs")
env.Append(LIBS=["pthread"])
diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp
index 4d45d3ba12..8277bb1505 100644
--- a/platform/linuxbsd/export/export_plugin.cpp
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -56,8 +56,8 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
}
String app_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- app_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ if (String(GLOBAL_GET("application/config/name")) != "") {
+ app_name = String(GLOBAL_GET("application/config/name"));
} else {
app_name = "Unnamed";
}
diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp
index fa3f7fbfea..88ec37c456 100644
--- a/platform/linuxbsd/freedesktop_screensaver.cpp
+++ b/platform/linuxbsd/freedesktop_screensaver.cpp
@@ -55,7 +55,7 @@ void FreeDesktopScreenSaver::inhibit() {
return;
}
- String app_name_string = ProjectSettings::get_singleton()->get("application/config/name");
+ String app_name_string = GLOBAL_GET("application/config/name");
CharString app_name_utf8 = app_name_string.utf8();
const char *app_name = app_name_string.is_empty() ? "Godot Engine" : app_name_utf8.get_data();
diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp
index 91a260182e..fa5e20891c 100644
--- a/platform/linuxbsd/godot_linuxbsd.cpp
+++ b/platform/linuxbsd/godot_linuxbsd.cpp
@@ -69,6 +69,7 @@ int main(int argc, char *argv[]) {
}
if (Main::start()) {
+ os.set_exit_code(EXIT_SUCCESS);
os.run(); // it is actually the OS that decides how to run
}
Main::cleanup();
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 995a904398..e14e4fb52d 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -40,7 +40,7 @@
#endif
#ifdef X11_ENABLED
-#include "display_server_x11.h"
+#include "x11/display_server_x11.h"
#endif
#ifdef HAVE_MNTENT
@@ -128,6 +128,8 @@ void OS_LinuxBSD::initialize() {
crash_handler.initialize();
OS_Unix::initialize_core();
+
+ system_dir_desktop_cache = get_system_dir(SYSTEM_DIR_DESKTOP);
}
void OS_LinuxBSD::initialize_joypads() {
@@ -246,6 +248,10 @@ String OS_LinuxBSD::get_version() const {
}
Vector<String> OS_LinuxBSD::get_video_adapter_driver_info() const {
+ if (RenderingServer::get_singleton()->get_rendering_device() == nullptr) {
+ return Vector<String>();
+ }
+
const String rendering_device_name = RenderingServer::get_singleton()->get_rendering_device()->get_device_name(); // e.g. `NVIDIA GeForce GTX 970`
const String rendering_device_vendor = RenderingServer::get_singleton()->get_rendering_device()->get_device_vendor_name(); // e.g. `NVIDIA`
const String card_name = rendering_device_name.trim_prefix(rendering_device_vendor).strip_edges(); // -> `GeForce GTX 970`
@@ -477,7 +483,16 @@ Error OS_LinuxBSD::shell_open(String p_uri) {
}
bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc";
+#ifdef FONTCONFIG_ENABLED
+ if (p_feature == "system_fonts") {
+ return font_config_initialized;
+ }
+#endif
+ if (p_feature == "pc") {
+ return true;
+ }
+
+ return false;
}
uint64_t OS_LinuxBSD::get_embedded_pck_offset() const {
@@ -619,6 +634,8 @@ String OS_LinuxBSD::get_system_font_path(const String &p_font_name, bool p_bold,
ERR_FAIL_V_MSG(String(), "Unable to load fontconfig, system font support is disabled.");
}
+ bool allow_substitutes = (p_font_name.to_lower() == "sans-serif") || (p_font_name.to_lower() == "serif") || (p_font_name.to_lower() == "monospace") || (p_font_name.to_lower() == "cursive") || (p_font_name.to_lower() == "fantasy");
+
String ret;
FcConfig *config = FcInitLoadConfigAndFonts();
@@ -640,6 +657,19 @@ String OS_LinuxBSD::get_system_font_path(const String &p_font_name, bool p_bold,
FcResult result;
FcPattern *match = FcFontMatch(0, pattern, &result);
if (match) {
+ if (!allow_substitutes) {
+ char *family_name = nullptr;
+ if (FcPatternGetString(match, FC_FAMILY, 0, reinterpret_cast<FcChar8 **>(&family_name)) == FcResultMatch) {
+ if (family_name && String::utf8(family_name).to_lower() != p_font_name.to_lower()) {
+ FcPatternDestroy(match);
+ FcPatternDestroy(pattern);
+ FcObjectSetDestroy(object_set);
+ FcConfigDestroy(config);
+
+ return String();
+ }
+ }
+ }
char *file_name = nullptr;
if (FcPatternGetString(match, FC_FILE, 0, reinterpret_cast<FcChar8 **>(&file_name)) == FcResultMatch) {
if (file_name) {
@@ -706,6 +736,10 @@ String OS_LinuxBSD::get_cache_path() const {
}
String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const {
+ if (p_dir == SYSTEM_DIR_DESKTOP && !system_dir_desktop_cache.is_empty()) {
+ return system_dir_desktop_cache;
+ }
+
String xdgparam;
switch (p_dir) {
@@ -714,31 +748,24 @@ String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
} break;
case SYSTEM_DIR_DCIM: {
xdgparam = "PICTURES";
-
} break;
case SYSTEM_DIR_DOCUMENTS: {
xdgparam = "DOCUMENTS";
-
} break;
case SYSTEM_DIR_DOWNLOADS: {
xdgparam = "DOWNLOAD";
-
} break;
case SYSTEM_DIR_MOVIES: {
xdgparam = "VIDEOS";
-
} break;
case SYSTEM_DIR_MUSIC: {
xdgparam = "MUSIC";
-
} break;
case SYSTEM_DIR_PICTURES: {
xdgparam = "PICTURES";
-
} break;
case SYSTEM_DIR_RINGTONES: {
xdgparam = "MUSIC";
-
} break;
}
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index aea04c1363..aa7af92aa1 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -72,6 +72,8 @@ class OS_LinuxBSD : public OS_Unix {
Vector<String> lspci_device_filter(Vector<String> vendor_device_id_mapping, String class_suffix, String check_column, String whitelist) const;
Vector<String> lspci_get_device_value(Vector<String> vendor_device_id_mapping, String check_column, String blacklist) const;
+ String system_dir_desktop_cache;
+
protected:
virtual void initialize() override;
virtual void finalize() override;
diff --git a/platform/linuxbsd/platform_config.h b/platform/linuxbsd/platform_config.h
index 3c05c67444..79e15e2512 100644
--- a/platform/linuxbsd/platform_config.h
+++ b/platform/linuxbsd/platform_config.h
@@ -44,4 +44,4 @@
#endif
#endif
-#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h"
+#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h"
diff --git a/platform/linuxbsd/x11/SCsub b/platform/linuxbsd/x11/SCsub
new file mode 100644
index 0000000000..30c6080355
--- /dev/null
+++ b/platform/linuxbsd/x11/SCsub
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+Import("env")
+
+source_files = [
+ "display_server_x11.cpp",
+ "key_mapping_x11.cpp",
+]
+
+if env["vulkan"]:
+ source_files.append("vulkan_context_x11.cpp")
+
+if env["opengl3"]:
+ source_files.append(["gl_manager_x11.cpp", "detect_prime_x11.cpp", "#thirdparty/glad/glx.c"])
+
+objects = []
+
+for source_file in source_files:
+ objects.append(env.Object(source_file))
+
+Return("objects")
diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/x11/detect_prime_x11.cpp
index fb833ab5e6..ed046432d8 100644
--- a/platform/linuxbsd/detect_prime_x11.cpp
+++ b/platform/linuxbsd/x11/detect_prime_x11.cpp
@@ -38,8 +38,9 @@
#include <stdlib.h>
-#include <GL/gl.h>
-#include <GL/glx.h>
+#include "thirdparty/glad/glad/gl.h"
+#include "thirdparty/glad/glad/glx.h"
+
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -77,8 +78,6 @@ void create_context() {
Window x11_window;
GLXContext glx_context;
- GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
-
static int visual_attribs[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
@@ -101,7 +100,7 @@ void create_context() {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
if (!fbc) {
- exit(1);
+ quick_exit(1);
}
vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
@@ -122,7 +121,7 @@ void create_context() {
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, 10, 10, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
if (!x11_window) {
- exit(1);
+ quick_exit(1);
}
glXMakeCurrent(x11_display, x11_window, glx_context);
@@ -189,8 +188,20 @@ int detect_prime() {
if (i) {
setenv("DRI_PRIME", "1", 1);
}
+
+ if (gladLoaderLoadGLX(NULL, 0) == 0) {
+ print_verbose("Unable to load GLX, GPU detection skipped.");
+ quick_exit(1);
+ }
+
create_context();
+ PFNGLGETSTRINGPROC glGetString = (PFNGLGETSTRINGPROC)glXGetProcAddressARB((GLubyte *)"glGetString");
+ if (!glGetString) {
+ print_verbose("Unable to get glGetString, GPU detection skipped.");
+ quick_exit(1);
+ }
+
const char *vendor = (const char *)glGetString(GL_VENDOR);
const char *renderer = (const char *)glGetString(GL_RENDERER);
@@ -208,7 +219,10 @@ int detect_prime() {
print_verbose("Couldn't write vendor/renderer string.");
}
close(fdset[1]);
- exit(0);
+
+ // The function quick_exit() is used because exit() will call destructors on static objects copied by fork().
+ // These objects will be freed anyway when the process finishes execution.
+ quick_exit(0);
}
}
diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/x11/detect_prime_x11.h
index 7eb7064cc5..7eb7064cc5 100644
--- a/platform/linuxbsd/detect_prime_x11.h
+++ b/platform/linuxbsd/x11/detect_prime_x11.h
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index e78467beff..cf50748ac8 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -126,7 +126,7 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
case FEATURE_WINDOW_TRANSPARENCY:
//case FEATURE_HIDPI:
case FEATURE_ICON:
- case FEATURE_NATIVE_ICON:
+ //case FEATURE_NATIVE_ICON:
case FEATURE_SWAP_BUFFERS:
#ifdef DBUS_ENABLED
case FEATURE_KEEP_SCREEN_ON:
@@ -376,10 +376,18 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
}
// The only modes that show a cursor are VISIBLE and CONFINED
- bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+ bool show_cursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+ bool previously_shown = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED);
+
+ if (show_cursor && !previously_shown) {
+ WindowID window_id = get_window_at_screen_position(mouse_get_position());
+ if (window_id != INVALID_WINDOW_ID) {
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
+ }
for (const KeyValue<WindowID, WindowData> &E : windows) {
- if (showCursor) {
+ if (show_cursor) {
XDefineCursor(x11_display, E.value.x11_window, cursors[current_cursor]); // show cursor
} else {
XDefineCursor(x11_display, E.value.x11_window, null_cursor); // hide cursor
@@ -1309,6 +1317,14 @@ int64_t DisplayServerX11::window_get_native_handle(HandleType p_handle_type, Win
case WINDOW_VIEW: {
return 0; // Not supported.
}
+#ifdef GLES3_ENABLED
+ case OPENGL_CONTEXT: {
+ if (gl_manager) {
+ return (int64_t)gl_manager->get_glx_context(p_window);
+ }
+ return 0;
+ }
+#endif
default: {
return 0;
}
@@ -3414,7 +3430,7 @@ bool DisplayServerX11::mouse_process_popups() {
XWindowAttributes root_attrs;
XGetWindowAttributes(x11_display, root, &root_attrs);
Vector2i pos = Vector2i(root_attrs.x + root_x, root_attrs.y + root_y);
- if ((pos != last_mouse_monitor_pos) || (mask != last_mouse_monitor_mask)) {
+ if (mask != last_mouse_monitor_mask) {
if (((mask & Button1Mask) || (mask & Button2Mask) || (mask & Button3Mask) || (mask & Button4Mask) || (mask & Button5Mask))) {
List<WindowID>::Element *C = nullptr;
List<WindowID>::Element *E = popup_list.back();
@@ -3440,7 +3456,6 @@ bool DisplayServerX11::mouse_process_popups() {
}
}
last_mouse_monitor_mask = mask;
- last_mouse_monitor_pos = pos;
}
}
return closed;
@@ -4113,10 +4128,10 @@ void DisplayServerX11::process_events() {
if (event.xselection.target == requested) {
Property p = _read_property(x11_display, windows[window_id].x11_window, XInternAtom(x11_display, "PRIMARY", 0));
- Vector<String> files = String((char *)p.data).split("\n", false);
+ Vector<String> files = String((char *)p.data).split("\r\n", false);
XFree(p.data);
for (int i = 0; i < files.size(); i++) {
- files.write[i] = files[i].replace("file://", "").uri_decode().strip_edges();
+ files.write[i] = files[i].replace("file://", "").uri_decode();
}
if (!windows[window_id].drop_files_callback.is_null()) {
@@ -4399,7 +4414,7 @@ void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo
#if defined(GLES3_ENABLED)
if (gl_manager) {
- gl_manager->set_use_vsync(p_vsync_mode == DisplayServer::VSYNC_ENABLED);
+ gl_manager->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
}
#endif
}
@@ -4432,13 +4447,24 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+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, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
- "Please update your drivers or if you have a very old or integrated GPU, upgrade it.\n"
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_name = OS::get_singleton()->get_executable_path().get_file();
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'./" +
+ executable_name + " --rendering-driver opengl3'.\n "
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
@@ -4649,6 +4675,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
if (gl_manager) {
Error err = gl_manager->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height);
ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window");
+ window_set_vsync_mode(p_vsync_mode, id);
}
#endif
@@ -4682,7 +4709,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
return id;
}
-DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
r_error = OK;
@@ -4909,6 +4936,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
+
+ if (p_position != nullptr) {
+ window_position = *p_position;
+ }
+
WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution));
if (main_window == INVALID_WINDOW_ID) {
r_error = ERR_CANT_CREATE;
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 5723abc751..4be8c3a534 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -47,7 +47,7 @@
#include "servers/rendering_server.h"
#if defined(SPEECHD_ENABLED)
-#include "tts_linux.h"
+#include "../tts_linux.h"
#endif
#if defined(GLES3_ENABLED)
@@ -56,12 +56,12 @@
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
-#include "platform/linuxbsd/vulkan_context_x11.h"
+#include "vulkan_context_x11.h"
#endif
#if defined(DBUS_ENABLED)
-#include "freedesktop_portal_desktop.h"
-#include "freedesktop_screensaver.h"
+#include "../freedesktop_portal_desktop.h"
+#include "../freedesktop_screensaver.h"
#endif
#include <X11/Xcursor/Xcursor.h>
@@ -169,7 +169,6 @@ class DisplayServerX11 : public DisplayServer {
HashMap<WindowID, WindowData> windows;
unsigned int last_mouse_monitor_mask = 0;
- Vector2i last_mouse_monitor_pos;
uint64_t time_since_popup = 0;
List<WindowID> popup_list;
@@ -444,12 +443,12 @@ public:
virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *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, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_x11_driver();
- DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerX11();
};
diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp
index f586c57dda..bcefcf9695 100644
--- a/platform/linuxbsd/gl_manager_x11.cpp
+++ b/platform/linuxbsd/x11/gl_manager_x11.cpp
@@ -37,9 +37,7 @@
#include <stdlib.h>
#include <unistd.h>
-#define GLX_GLXEXT_PROTOTYPES
-#include <GL/glx.h>
-#include <GL/glxext.h>
+#include "thirdparty/glad/glad/glx.h"
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
@@ -324,15 +322,14 @@ void GLManager_X11::swap_buffers() {
}
Error GLManager_X11::initialize() {
+ if (!gladLoaderLoadGLX(nullptr, 0)) {
+ return ERR_CANT_CREATE;
+ }
+
return OK;
}
void GLManager_X11::set_use_vsync(bool p_use) {
- static bool setup = false;
- static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr;
- static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr;
- static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr;
-
// force vsync in the editor for now, as a safety measure
bool is_editor = Engine::get_singleton()->is_editor_hint();
if (is_editor) {
@@ -345,25 +342,12 @@ void GLManager_X11::set_use_vsync(bool p_use) {
}
const GLDisplay &disp = get_current_display();
- if (!setup) {
- setup = true;
- String extensions = glXQueryExtensionsString(disp.x11_display, DefaultScreen(disp.x11_display));
- if (extensions.find("GLX_EXT_swap_control") != -1) {
- glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT");
- }
- if (extensions.find("GLX_MESA_swap_control") != -1) {
- glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA");
- }
- if (extensions.find("GLX_SGI_swap_control") != -1) {
- glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI");
- }
- }
int val = p_use ? 1 : 0;
- if (glXSwapIntervalMESA) {
+ if (GLAD_GLX_MESA_swap_control) {
glXSwapIntervalMESA(val);
- } else if (glXSwapIntervalSGI) {
+ } else if (GLAD_GLX_SGI_swap_control) {
glXSwapIntervalSGI(val);
- } else if (glXSwapIntervalEXT) {
+ } else if (GLAD_GLX_EXT_swap_control) {
GLXDrawable drawable = glXGetCurrentDrawable();
glXSwapIntervalEXT(disp.x11_display, drawable, val);
} else {
@@ -376,6 +360,17 @@ bool GLManager_X11::is_using_vsync() const {
return use_vsync;
}
+void *GLManager_X11::get_glx_context(DisplayServer::WindowID p_window_id) {
+ if (p_window_id == -1) {
+ return nullptr;
+ }
+
+ const GLWindow &win = _windows[p_window_id];
+ const GLDisplay &disp = get_display(win.gldisplay_id);
+
+ return (void *)disp.context->glx_context;
+}
+
GLManager_X11::GLManager_X11(const Vector2i &p_size, ContextType p_context_type) {
context_type = p_context_type;
diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/x11/gl_manager_x11.h
index 4f78c45c88..1594c82801 100644
--- a/platform/linuxbsd/gl_manager_x11.h
+++ b/platform/linuxbsd/x11/gl_manager_x11.h
@@ -116,6 +116,8 @@ public:
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
+ void *get_glx_context(DisplayServer::WindowID p_window_id);
+
GLManager_X11(const Vector2i &p_size, ContextType p_context_type);
~GLManager_X11();
};
diff --git a/platform/linuxbsd/key_mapping_x11.cpp b/platform/linuxbsd/x11/key_mapping_x11.cpp
index f774c99d99..f774c99d99 100644
--- a/platform/linuxbsd/key_mapping_x11.cpp
+++ b/platform/linuxbsd/x11/key_mapping_x11.cpp
diff --git a/platform/linuxbsd/key_mapping_x11.h b/platform/linuxbsd/x11/key_mapping_x11.h
index b7b8a3b787..b7b8a3b787 100644
--- a/platform/linuxbsd/key_mapping_x11.h
+++ b/platform/linuxbsd/x11/key_mapping_x11.h
diff --git a/platform/linuxbsd/vulkan_context_x11.cpp b/platform/linuxbsd/x11/vulkan_context_x11.cpp
index b4f585726f..92aaf33b05 100644
--- a/platform/linuxbsd/vulkan_context_x11.cpp
+++ b/platform/linuxbsd/x11/vulkan_context_x11.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef VULKAN_ENABLED
+
#include "vulkan_context_x11.h"
#ifdef USE_VOLK
@@ -59,3 +61,5 @@ VulkanContextX11::VulkanContextX11() {
VulkanContextX11::~VulkanContextX11() {
}
+
+#endif // VULKAN_ENABLED
diff --git a/platform/linuxbsd/vulkan_context_x11.h b/platform/linuxbsd/x11/vulkan_context_x11.h
index 0c4a6cd278..0adb50ef44 100644
--- a/platform/linuxbsd/vulkan_context_x11.h
+++ b/platform/linuxbsd/x11/vulkan_context_x11.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_X11_H
#define VULKAN_CONTEXT_X11_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
#include <X11/Xlib.h>
@@ -44,4 +46,6 @@ public:
~VulkanContextX11();
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_X11_H
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 511286d52b..67e4b49b14 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -223,6 +223,8 @@ def configure(env: "Environment"):
"AVFoundation",
"-framework",
"CoreMedia",
+ "-framework",
+ "QuartzCore",
]
)
env.Append(LIBS=["pthread", "z"])
@@ -236,22 +238,28 @@ def configure(env: "Environment"):
if env["vulkan"]:
env.Append(CPPDEFINES=["VULKAN_ENABLED"])
- env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "QuartzCore", "-framework", "IOSurface"])
+ env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "IOSurface"])
if not env["use_volk"]:
env.Append(LINKFLAGS=["-lMoltenVK"])
mvk_found = False
+
+ mkv_list = [get_mvk_sdk_path(), "/opt/homebrew/lib", "/usr/local/homebrew/lib", "/opt/local/lib"]
if env["vulkan_sdk_path"] != "":
- mvk_path = os.path.join(
- os.path.expanduser(env["vulkan_sdk_path"]), "MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/"
+ mkv_list.insert(0, os.path.expanduser(env["vulkan_sdk_path"]))
+ mkv_list.insert(
+ 0,
+ os.path.join(
+ os.path.expanduser(env["vulkan_sdk_path"]), "MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/"
+ ),
)
- if os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")):
- mvk_found = True
- env.Append(LINKFLAGS=["-L" + mvk_path])
- if not mvk_found:
- mvk_path = get_mvk_sdk_path()
+
+ for mvk_path in mkv_list:
if mvk_path and os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")):
mvk_found = True
+ print("MoltenVK found at: " + mvk_path)
env.Append(LINKFLAGS=["-L" + mvk_path])
+ break
+
if not mvk_found:
print(
"MoltenVK SDK installation directory not found, use 'vulkan_sdk_path' SCons parameter to specify SDK path."
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 484b8ffebc..8f315f736b 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -106,6 +106,7 @@ public:
bool layered_window = false;
bool fullscreen = false;
+ bool exclusive_fullscreen = false;
bool on_top = false;
bool borderless = false;
bool resize_disabled = false;
@@ -232,6 +233,7 @@ public:
void popup_close(WindowID p_window);
void set_is_resizing(bool p_is_resizing);
bool get_is_resizing() const;
+ void reparent_check(WindowID p_window);
void window_update(WindowID p_window);
void window_destroy(WindowID p_window);
@@ -430,12 +432,12 @@ public:
virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *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, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_macos_driver();
- DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerMacOS();
};
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index f4692abc92..3aff5b8b7e 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -166,6 +166,7 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
Error err = gl_manager->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height);
ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context");
}
+ window_set_vsync_mode(p_vsync_mode, window_id_counter);
#endif
[wd.window_view updateLayerDelegate];
id = window_id_counter++;
@@ -1843,11 +1844,22 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
window_id = MAIN_WINDOW_ID;
}
WindowData &wd = windows[window_id];
+
+ bool show_cursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+ bool previously_shown = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED);
+
+ if (show_cursor && !previously_shown) {
+ WindowID window_id = get_window_at_screen_position(mouse_get_position());
+ if (window_id != INVALID_WINDOW_ID) {
+ send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
+ }
+
if (p_mode == MOUSE_MODE_CAPTURED) {
// Apple Docs state that the display parameter is not used.
// "This parameter is not used. By default, you may pass kCGDirectMainDisplay."
// https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/Quartz_Services_Ref/Reference/reference.html
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (previously_shown) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
CGAssociateMouseAndMouseCursorPosition(false);
@@ -1858,7 +1870,7 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y };
CGWarpMouseCursorPosition(lMouseWarpPos);
} else if (p_mode == MOUSE_MODE_HIDDEN) {
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (previously_shown) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
[wd.window_object setMovable:YES];
@@ -1868,7 +1880,7 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
[wd.window_object setMovable:NO];
CGAssociateMouseAndMouseCursorPosition(false);
} else if (p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (previously_shown) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
[wd.window_object setMovable:NO];
@@ -1884,7 +1896,7 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
warp_events.clear();
mouse_mode = p_mode;
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (show_cursor) {
cursor_update_shape();
}
}
@@ -2179,7 +2191,7 @@ void DisplayServerMacOS::screen_set_keep_on(bool p_enable) {
}
if (p_enable) {
- String app_name_string = ProjectSettings::get_singleton()->get("application/config/name");
+ String app_name_string = GLOBAL_GET("application/config/name");
NSString *name = [NSString stringWithUTF8String:(app_name_string.is_empty() ? "Godot Engine" : app_name_string.utf8().get_data())];
NSString *reason = @"Godot Engine running with display/window/energy_saving/keep_screen_on = true";
IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep, (__bridge CFStringRef)name, (__bridge CFStringRef)reason, (__bridge CFStringRef)reason, nullptr, 0, nullptr, &screen_keep_on_assertion);
@@ -2325,22 +2337,64 @@ void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_wind
}
}
-void DisplayServerMacOS::window_set_exclusive(WindowID p_window, bool p_exclusive) {
- _THREAD_SAFE_METHOD_
+void DisplayServerMacOS::reparent_check(WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- if (wd.exclusive != p_exclusive) {
- wd.exclusive = p_exclusive;
- if (wd.transient_parent != INVALID_WINDOW_ID) {
- WindowData &wd_parent = windows[wd.transient_parent];
- if (wd.exclusive) {
- ERR_FAIL_COND_MSG([[wd_parent.window_object childWindows] count] > 0, "Transient parent has another exclusive child.");
+ NSScreen *screen = [wd.window_object screen];
+
+ if (wd.transient_parent != INVALID_WINDOW_ID) {
+ WindowData &wd_parent = windows[wd.transient_parent];
+ NSScreen *parent_screen = [wd_parent.window_object screen];
+
+ if (parent_screen == screen) {
+ if (![[wd_parent.window_object childWindows] containsObject:wd.window_object]) {
+ if (wd.exclusive) {
+ ERR_FAIL_COND_MSG([[wd_parent.window_object childWindows] count] > 0, "Transient parent has another exclusive child.");
+ }
+ [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
[wd_parent.window_object addChildWindow:wd.window_object ordered:NSWindowAbove];
- } else {
+ }
+ } else {
+ if ([[wd_parent.window_object childWindows] containsObject:wd.window_object]) {
[wd_parent.window_object removeChildWindow:wd.window_object];
+ [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ [wd.window_object orderFront:nil];
}
}
}
+
+ for (const WindowID &child : wd.transient_children) {
+ WindowData &wd_child = windows[child];
+ NSScreen *child_screen = [wd_child.window_object screen];
+
+ if (child_screen == screen) {
+ if (![[wd.window_object childWindows] containsObject:wd_child.window_object]) {
+ if (wd_child.exclusive) {
+ ERR_FAIL_COND_MSG([[wd.window_object childWindows] count] > 0, "Transient parent has another exclusive child.");
+ }
+ if (wd_child.fullscreen) {
+ [wd_child.window_object toggleFullScreen:nil];
+ }
+ [wd_child.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
+ [wd.window_object addChildWindow:wd_child.window_object ordered:NSWindowAbove];
+ }
+ } else {
+ if ([[wd.window_object childWindows] containsObject:wd_child.window_object]) {
+ [wd.window_object removeChildWindow:wd_child.window_object];
+ [wd_child.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ }
+ }
+ }
+}
+
+void DisplayServerMacOS::window_set_exclusive(WindowID p_window, bool p_exclusive) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ if (wd.exclusive != p_exclusive) {
+ wd.exclusive = p_exclusive;
+ reparent_check(p_window);
+ }
}
Point2i DisplayServerMacOS::window_get_position(WindowID p_window) const {
@@ -2417,11 +2471,10 @@ void DisplayServerMacOS::window_set_transient(WindowID p_window, WindowID p_pare
wd_window.transient_parent = INVALID_WINDOW_ID;
wd_parent.transient_children.erase(p_window);
- [wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
-
- if (wd_window.exclusive) {
+ if ([[wd_parent.window_object childWindows] containsObject:wd_window.window_object]) {
[wd_parent.window_object removeChildWindow:wd_window.window_object];
}
+ [wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
} else {
ERR_FAIL_COND(!windows.has(p_parent));
ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
@@ -2429,11 +2482,7 @@ void DisplayServerMacOS::window_set_transient(WindowID p_window, WindowID p_pare
wd_window.transient_parent = p_parent;
wd_parent.transient_children.insert(p_window);
- [wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
-
- if (wd_window.exclusive) {
- [wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove];
- }
+ reparent_check(p_window);
}
}
@@ -2573,7 +2622,13 @@ void DisplayServerMacOS::window_set_mode(WindowMode p_mode, WindowID p_window) {
[wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
}
[wd.window_object toggleFullScreen:nil];
+
+ if (old_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
+ [NSApp setPresentationOptions:NSApplicationPresentationDefault];
+ }
+
wd.fullscreen = false;
+ wd.exclusive_fullscreen = false;
} break;
case WINDOW_MODE_MAXIMIZED: {
if ([wd.window_object isZoomed]) {
@@ -2598,7 +2653,15 @@ void DisplayServerMacOS::window_set_mode(WindowMode p_mode, WindowID p_window) {
[wd.window_object setContentMinSize:NSMakeSize(0, 0)];
[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[wd.window_object toggleFullScreen:nil];
+
wd.fullscreen = true;
+ if (p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
+ const NSUInteger presentationOptions = NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
+ [NSApp setPresentationOptions:presentationOptions];
+ wd.exclusive_fullscreen = true;
+ } else {
+ wd.exclusive_fullscreen = false;
+ }
} break;
case WINDOW_MODE_MAXIMIZED: {
if (![wd.window_object isZoomed]) {
@@ -2615,7 +2678,11 @@ DisplayServer::WindowMode DisplayServerMacOS::window_get_mode(WindowID p_window)
const WindowData &wd = windows[p_window];
if (wd.fullscreen) { // If fullscreen, it's not in another mode.
- return WINDOW_MODE_FULLSCREEN;
+ if (wd.exclusive_fullscreen) {
+ return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
+ } else {
+ return WINDOW_MODE_FULLSCREEN;
+ }
}
if ([wd.window_object isZoomed] && !wd.resize_disabled) {
return WINDOW_MODE_MAXIMIZED;
@@ -2932,6 +2999,14 @@ int64_t DisplayServerMacOS::window_get_native_handle(HandleType p_handle_type, W
case WINDOW_VIEW: {
return (int64_t)windows[p_window].window_view;
}
+#ifdef GLES3_ENABLED
+ case OPENGL_CONTEXT: {
+ if (gl_manager) {
+ return (int64_t)gl_manager->get_context(p_window);
+ }
+ return 0;
+ }
+#endif
default: {
return 0;
}
@@ -2962,7 +3037,7 @@ void DisplayServerMacOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_
_THREAD_SAFE_METHOD_
#if defined(GLES3_ENABLED)
if (gl_manager) {
- gl_manager->set_use_vsync(p_vsync_mode);
+ gl_manager->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -3405,10 +3480,29 @@ void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) {
[NSApp setApplicationIconImage:nsimg];
}
-DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerMacOS::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, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.", "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_command;
+ if (OS::get_singleton()->get_bundle_resource_dir() == OS::get_singleton()->get_executable_path().get_base_dir()) {
+ executable_command = vformat("%s --rendering-driver opengl3", OS::get_singleton()->get_executable_path());
+ } else {
+ executable_command = vformat("open %s --args --rendering-driver opengl3", OS::get_singleton()->get_bundle_resource_dir().path_join("../..").simplify_path());
+ }
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command: '" +
+ executable_command + "'.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
@@ -3556,7 +3650,7 @@ bool DisplayServerMacOS::mouse_process_popups(bool p_close) {
return closed;
}
-DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
r_error = OK;
@@ -3665,6 +3759,11 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
Point2i window_position(
screen_get_position(0).x + (screen_get_size(0).width - p_resolution.width) / 2,
screen_get_position(0).y + (screen_get_size(0).height - p_resolution.height) / 2);
+
+ if (p_position != nullptr) {
+ window_position = *p_position;
+ }
+
WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution));
ERR_FAIL_COND(main_window == INVALID_WINDOW_ID);
for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index f5f64f9663..5860a4f0ae 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -34,6 +34,7 @@
#include "lipo.h"
#include "macho.h"
+#include "core/io/image_loader.h"
#include "core/string/translation.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
@@ -116,7 +117,8 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.icns,*.png,*.webp,*.svg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games"));
@@ -268,7 +270,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
memcpy(&p_dest.write[ofs], result.ptr(), res_size);
}
-void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
+void EditorExportPlatformMacOS::_make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
Ref<ImageTexture> it = memnew(ImageTexture);
Vector<uint8_t> data;
@@ -302,7 +304,7 @@ void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint
for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy?
copy->convert(Image::FORMAT_RGBA8);
- copy->resize(icon_infos[i].size, icon_infos[i].size);
+ copy->resize(icon_infos[i].size, icon_infos[i].size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
if (icon_infos[i].is_png) {
// Encode PNG icon.
@@ -383,7 +385,7 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres
if (lines[i].find("$binary") != -1) {
strnew += lines[i].replace("$binary", p_binary) + "\n";
} else if (lines[i].find("$name") != -1) {
- strnew += lines[i].replace("$name", ProjectSettings::get_singleton()->get("application/config/name")) + "\n";
+ strnew += lines[i].replace("$name", GLOBAL_GET("application/config/name")) + "\n";
} else if (lines[i].find("$bundle_identifier") != -1) {
strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
} else if (lines[i].find("$short_version") != -1) {
@@ -473,7 +475,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
case 1: { // "rcodesign"
print_verbose("using rcodesign notarization...");
- String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
return Error::FAILED;
@@ -636,7 +638,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
case 2: { // "rcodesign"
print_verbose("using rcodesign codesign...");
- String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xrcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
return Error::FAILED;
@@ -726,7 +728,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
String str;
int exitcode = 0;
- Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true);
+ Error err = OS::get_singleton()->execute("codesign", args, &str, &exitcode, true);
if (err != OK) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed."));
return err;
@@ -982,8 +984,8 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String binary_to_use = "godot_macos_" + String(p_debug ? "debug" : "release") + "." + architecture;
String pkg_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ if (String(GLOBAL_GET("application/config/name")) != "") {
+ pkg_name = String(GLOBAL_GET("application/config/name"));
} else {
pkg_name = "Unnamed";
}
@@ -1073,7 +1075,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
- Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
+ Dictionary appnames = GLOBAL_GET("application/config/name_localized");
Dictionary microphone_usage_descriptions = p_preset->get("privacy/microphone_usage_description_localized");
Dictionary camera_usage_descriptions = p_preset->get("privacy/camera_usage_description_localized");
Dictionary location_usage_descriptions = p_preset->get("privacy/location_usage_description_localized");
@@ -1087,7 +1089,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
Dictionary removable_volumes_usage_descriptions = p_preset->get("privacy/removable_volumes_usage_description_localized");
Dictionary copyrights = p_preset->get("application/copyright_localized");
- Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
{
String fname = tmp_app_path_name + "/Contents/Resources/en.lproj";
@@ -1095,7 +1097,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
f->store_line("/* Localized versions of Info.plist keys */");
f->store_line("");
- f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";");
+ f->store_line("CFBundleDisplayName = \"" + GLOBAL_GET("application/config/name").operator String() + "\";");
if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) {
f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String() + "\";");
}
@@ -1257,7 +1259,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (p_preset->get("application/icon") != "") {
iconpath = p_preset->get("application/icon");
} else {
- iconpath = ProjectSettings::get_singleton()->get("application/config/icon");
+ iconpath = GLOBAL_GET("application/config/icon");
}
if (!iconpath.is_empty()) {
@@ -1270,9 +1272,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
} else {
Ref<Image> icon;
icon.instantiate();
- icon->load(iconpath);
- if (!icon->is_empty()) {
- _make_icon(icon, data);
+ err = ImageLoader::load_image(iconpath, icon);
+ if (err == OK && !icon->is_empty()) {
+ _make_icon(p_preset, icon, data);
}
}
}
@@ -1852,7 +1854,7 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
valid = false;
}
- String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
err += TTR("Notarization: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
valid = false;
@@ -1875,7 +1877,7 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
valid = false;
}
} else if (codesign_tool == 2) {
- String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
err += TTR("Code signing: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
valid = false;
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index b6ad587caa..af7570c394 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -53,7 +53,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
Ref<ImageTexture> logo;
void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
- void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
+ void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true);
diff --git a/platform/macos/gl_manager_macos_legacy.h b/platform/macos/gl_manager_macos_legacy.h
index 8752086551..d7ad5b1197 100644
--- a/platform/macos/gl_manager_macos_legacy.h
+++ b/platform/macos/gl_manager_macos_legacy.h
@@ -89,6 +89,8 @@ public:
void set_use_vsync(bool p_use);
bool is_using_vsync() const;
+ NSOpenGLContext *get_context(DisplayServer::WindowID p_window_id);
+
GLManager_MacOS(ContextType p_context_type);
~GLManager_MacOS();
};
diff --git a/platform/macos/gl_manager_macos_legacy.mm b/platform/macos/gl_manager_macos_legacy.mm
index dec4821b86..ea5c36da6c 100644
--- a/platform/macos/gl_manager_macos_legacy.mm
+++ b/platform/macos/gl_manager_macos_legacy.mm
@@ -215,6 +215,15 @@ bool GLManager_MacOS::is_using_vsync() const {
return use_vsync;
}
+NSOpenGLContext *GLManager_MacOS::get_context(DisplayServer::WindowID p_window_id) {
+ if (!windows.has(p_window_id)) {
+ return nullptr;
+ }
+
+ GLWindow &win = windows[p_window_id];
+ return win.context;
+}
+
GLManager_MacOS::GLManager_MacOS(ContextType p_context_type) {
context_type = p_context_type;
}
diff --git a/platform/macos/godot_application_delegate.mm b/platform/macos/godot_application_delegate.mm
index bacdcc2bc4..f1168c685a 100644
--- a/platform/macos/godot_application_delegate.mm
+++ b/platform/macos/godot_application_delegate.mm
@@ -61,7 +61,9 @@
- (void)applicationDidFinishLaunching:(NSNotification *)notice {
NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
- if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO)) {
+ NSString *nsbundleid_env = [NSString stringWithUTF8String:getenv("__CFBundleIdentifier")];
+ NSString *nsbundleid = [[NSBundle mainBundle] bundleIdentifier];
+ if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO) || ![nsbundleid isEqualToString:nsbundleid_env]) {
// If the executable is started from terminal or is not bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
[self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
}
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index 279fd2a359..27efd3ebb2 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -147,7 +147,12 @@
}
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ if (wd.exclusive_fullscreen) {
+ [NSApp setPresentationOptions:NSApplicationPresentationDefault];
+ }
+
wd.fullscreen = false;
+ wd.exclusive_fullscreen = false;
[(GodotWindow *)wd.window_object setAnimDuration:-1.0f];
@@ -251,6 +256,15 @@
}
}
+- (void)windowDidChangeScreen:(NSNotification *)notification {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (!ds || !ds->has_window(window_id)) {
+ return;
+ }
+
+ ds->reparent_check(window_id);
+}
+
- (void)windowDidMove:(NSNotification *)notification {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (!ds || !ds->has_window(window_id)) {
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index 8ffb0abfdb..e620b058d3 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -499,7 +499,14 @@ String OS_MacOS::get_unique_id() const {
}
bool OS_MacOS::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc";
+ if (p_feature == "system_fonts") {
+ return true;
+ }
+ if (p_feature == "pc") {
+ return true;
+ }
+
+ return false;
}
void OS_MacOS::disable_crash_handler() {
diff --git a/platform/macos/platform_config.h b/platform/macos/platform_config.h
index e114606b82..46c46b8803 100644
--- a/platform/macos/platform_config.h
+++ b/platform/macos/platform_config.h
@@ -30,5 +30,5 @@
#include <alloca.h>
-#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h"
+#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h"
#define PTHREAD_RENAME_SELF
diff --git a/platform/macos/vulkan_context_macos.h b/platform/macos/vulkan_context_macos.h
index 579c42b042..2a81336994 100644
--- a/platform/macos/vulkan_context_macos.h
+++ b/platform/macos/vulkan_context_macos.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_MACOS_H
#define VULKAN_CONTEXT_MACOS_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
#import <AppKit/AppKit.h>
@@ -44,4 +46,6 @@ public:
~VulkanContextMacOS();
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_MACOS_H
diff --git a/platform/macos/vulkan_context_macos.mm b/platform/macos/vulkan_context_macos.mm
index cf317f3c68..1df6b3ed18 100644
--- a/platform/macos/vulkan_context_macos.mm
+++ b/platform/macos/vulkan_context_macos.mm
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef VULKAN_ENABLED
#include "vulkan_context_macos.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -57,3 +58,5 @@ VulkanContextMacOS::VulkanContextMacOS() {
VulkanContextMacOS::~VulkanContextMacOS() {
}
+
+#endif // VULKAN_ENABLED
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 4e4afb9704..ab0b20762f 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -442,7 +442,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
#ifdef WINDOWS_ENABLED
// Sign with signtool
- String signtool_path = EditorSettings::get_singleton()->get("export/uwp/signtool");
+ String signtool_path = EDITOR_GET("export/uwp/signtool");
if (signtool_path.is_empty()) {
return OK;
}
@@ -454,9 +454,9 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
static String algs[] = { "MD5", "SHA1", "SHA256" };
- String cert_path = EditorSettings::get_singleton()->get("export/uwp/debug_certificate");
- String cert_pass = EditorSettings::get_singleton()->get("export/uwp/debug_password");
- int cert_alg = EditorSettings::get_singleton()->get("export/uwp/debug_algorithm");
+ String cert_path = EDITOR_GET("export/uwp/debug_certificate");
+ String cert_pass = EDITOR_GET("export/uwp/debug_password");
+ int cert_alg = EDITOR_GET("export/uwp/debug_algorithm");
if (!p_debug) {
cert_path = p_preset->get("signing/certificate");
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
index b0427d1a65..74b9ab4875 100644
--- a/platform/uwp/export/export_plugin.h
+++ b/platform/uwp/export/export_plugin.h
@@ -213,7 +213,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
String architecture = arch == "arm32" ? "arm" : (arch == "x86_32" ? "x86" : "x64");
result = result.replace("$architecture$", architecture);
- result = result.replace("$display_name$", String(p_preset->get("package/display_name")).is_empty() ? (String)ProjectSettings::get_singleton()->get("application/config/name") : String(p_preset->get("package/display_name")));
+ result = result.replace("$display_name$", String(p_preset->get("package/display_name")).is_empty() ? (String)GLOBAL_GET("application/config/name") : String(p_preset->get("package/display_name")));
result = result.replace("$publisher_display_name$", p_preset->get("package/publisher_display_name"));
result = result.replace("$app_description$", p_preset->get("package/description"));
diff --git a/platform/web/SCsub b/platform/web/SCsub
index cb00fa9f5b..077024507a 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -35,6 +35,7 @@ sys_env.AddJSLibraries(
"js/libs/library_godot_os.js",
"js/libs/library_godot_runtime.js",
"js/libs/library_godot_input.js",
+ "js/libs/library_godot_webgl2.js",
]
)
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index f6a61b18e4..f704124704 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -54,7 +54,15 @@ DisplayServerWeb *DisplayServerWeb::get_singleton() {
// Window (canvas)
bool DisplayServerWeb::check_size_force_redraw() {
- return godot_js_display_size_update() != 0;
+ bool size_changed = godot_js_display_size_update() != 0;
+ if (size_changed && !rect_changed_callback.is_null()) {
+ Variant size = Rect2i(Point2i(), window_get_size()); // TODO use window_get_position if implemented.
+ Variant *vp = &size;
+ Variant ret;
+ Callable::CallError ce;
+ rect_changed_callback.callp((const Variant **)&vp, 1, ret, ce);
+ }
+ return size_changed;
}
void DisplayServerWeb::fullscreen_change_callback(int p_fullscreen) {
@@ -212,7 +220,7 @@ int DisplayServerWeb::mouse_button_callback(int p_pressed, int p_button, double
void DisplayServerWeb::mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers) {
MouseButton input_mask = Input::get_singleton()->get_mouse_button_mask();
// For motion outside the canvas, only read mouse movement if dragging
- // started inside the canvas; imitating desktop app behaviour.
+ // started inside the canvas; imitating desktop app behavior.
if (!get_singleton()->cursor_inside_canvas && input_mask == MouseButton::NONE) {
return;
}
@@ -738,11 +746,11 @@ void DisplayServerWeb::_dispatch_input_event(const Ref<InputEvent> &p_event) {
}
}
-DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) {
- return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error) {
+ return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
}
-DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) {
+DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error) {
r_error = OK; // Always succeeds for now.
// Ensure the canvas ID.
@@ -758,10 +766,8 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
godot_js_os_request_quit_cb(request_quit_callback);
#ifdef GLES3_ENABLED
- // TODO "vulkan" defaults to webgl2 for now.
- bool wants_webgl2 = p_rendering_driver == "opengl3" || p_rendering_driver == "vulkan";
- bool webgl2_init_failed = wants_webgl2 && !godot_js_display_has_webgl(2);
- if (wants_webgl2 && !webgl2_init_failed) {
+ bool webgl2_inited = false;
+ if (godot_js_display_has_webgl(2)) {
EmscriptenWebGLContextAttributes attributes;
emscripten_webgl_init_context_attributes(&attributes);
attributes.alpha = OS::get_singleton()->is_layered_allowed();
@@ -770,17 +776,17 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
attributes.explicitSwapControl = true;
webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes);
- if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
- webgl2_init_failed = true;
- } else {
- RasterizerGLES3::make_current();
- }
+ webgl2_inited = webgl_ctx && emscripten_webgl_make_context_current(webgl_ctx) == EMSCRIPTEN_RESULT_SUCCESS;
}
- if (webgl2_init_failed) {
+ if (webgl2_inited) {
+ if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) {
+ print_verbose("Failed to enable WebXR extension.");
+ }
+ RasterizerGLES3::make_current();
+
+ } else {
OS::get_singleton()->alert("Your browser does not seem to support WebGL2. Please update your browser version.",
"Unable to initialize video driver");
- }
- if (!wants_webgl2 || webgl2_init_failed) {
RasterizerDummy::make_current();
}
#else
@@ -905,7 +911,7 @@ ObjectID DisplayServerWeb::window_get_attached_instance_id(WindowID p_window) co
}
void DisplayServerWeb::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
- // Not supported.
+ rect_changed_callback = p_callable;
}
void DisplayServerWeb::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h
index 85076b906f..1919736802 100644
--- a/platform/web/display_server_web.h
+++ b/platform/web/display_server_web.h
@@ -60,6 +60,7 @@ private:
WindowMode window_mode = WINDOW_MODE_WINDOWED;
ObjectID window_attached_instance_id = {};
+ Callable rect_changed_callback;
Callable window_event_callback;
Callable input_event_callback;
Callable input_text_callback;
@@ -96,7 +97,7 @@ private:
static void _js_utterance_callback(int p_event, int p_id, int p_pos);
static Vector<String> get_rendering_drivers_func();
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static void _dispatch_input_event(const Ref<InputEvent> &p_event);
@@ -221,7 +222,7 @@ public:
virtual void swap_buffers() override;
static void register_web_driver();
- DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error);
+ DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error);
~DisplayServerWeb();
};
diff --git a/platform/web/godot_webgl2.h b/platform/web/godot_webgl2.h
index 968b70f84b..ae6b23ae18 100644
--- a/platform/web/godot_webgl2.h
+++ b/platform/web/godot_webgl2.h
@@ -34,4 +34,21 @@
#include "GLES3/gl3.h"
#include "webgl/webgl2.h"
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
+#define GL_MAX_VIEWS_OVR 0x9631
+#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void godot_webgl2_glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+
+#define glFramebufferTextureMultiviewOVR godot_webgl2_glFramebufferTextureMultiviewOVR
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // GODOT_WEBGL2_H
diff --git a/platform/web/js/engine/config.js b/platform/web/js/engine/config.js
index 41be7b2512..4560f12b49 100644
--- a/platform/web/js/engine/config.js
+++ b/platform/web/js/engine/config.js
@@ -275,7 +275,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-
'print': this.onPrint,
'printErr': this.onPrintError,
'thisProgram': this.executable,
- 'noExitRuntime': true,
+ 'noExitRuntime': false,
'dynamicLibraries': [`${loadPath}.side.wasm`],
'instantiateWasm': function (imports, onSuccess) {
function done(result) {
diff --git a/platform/web/js/libs/library_godot_webgl2.js b/platform/web/js/libs/library_godot_webgl2.js
new file mode 100644
index 0000000000..365f712be7
--- /dev/null
+++ b/platform/web/js/libs/library_godot_webgl2.js
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* library_godot_webgl2.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+const GodotWebGL2 = {
+ $GodotWebGL2__deps: ['$GL', '$GodotRuntime'],
+ $GodotWebGL2: {},
+
+ godot_webgl2_glFramebufferTextureMultiviewOVR__deps: ['emscripten_webgl_get_current_context'],
+ godot_webgl2_glFramebufferTextureMultiviewOVR__proxy: 'sync',
+ godot_webgl2_glFramebufferTextureMultiviewOVR__sig: 'viiiiii',
+ godot_webgl2_glFramebufferTextureMultiviewOVR: function (target, attachment, texture, level, base_view_index, num_views) {
+ const context = GL.currentContext;
+ if (typeof context.multiviewExt === 'undefined') {
+ const ext = context.GLctx.getExtension('OVR_multiview2');
+ if (!ext) {
+ console.error('Trying to call glFramebufferTextureMultiviewOVR() without the OVR_multiview2 extension');
+ return;
+ }
+ context.multiviewExt = ext;
+ }
+ context.multiviewExt.framebufferTextureMultiviewOVR(target, attachment, GL.textures[texture], level, base_view_index, num_views);
+ },
+};
+
+autoAddDeps(GodotWebGL2, '$GodotWebGL2');
+mergeInto(LibraryManager.library, GodotWebGL2);
diff --git a/platform/web/package-lock.json b/platform/web/package-lock.json
index 4c12c8602d..e1428546c6 100644
--- a/platform/web/package-lock.json
+++ b/platform/web/package-lock.json
@@ -1686,9 +1686,9 @@
"dev": true
},
"node_modules/minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -3791,9 +3791,9 @@
"dev": true
},
"minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
diff --git a/platform/web/web_main.cpp b/platform/web/web_main.cpp
index a76b98f4e9..fce782b546 100644
--- a/platform/web/web_main.cpp
+++ b/platform/web/web_main.cpp
@@ -41,30 +41,25 @@
static OS_Web *os = nullptr;
static uint64_t target_ticks = 0;
+static bool main_started = false;
+static bool shutdown_complete = false;
void exit_callback() {
- emscripten_cancel_main_loop(); // After this, we can exit!
- Main::cleanup();
+ if (!shutdown_complete) {
+ return; // Still waiting.
+ }
+ if (main_started) {
+ Main::cleanup();
+ main_started = false;
+ }
int exit_code = OS_Web::get_singleton()->get_exit_code();
memdelete(os);
os = nullptr;
- emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing.
+ emscripten_force_exit(exit_code); // Exit runtime.
}
void cleanup_after_sync() {
- emscripten_set_main_loop(exit_callback, -1, false);
-}
-
-void early_cleanup() {
- emscripten_cancel_main_loop(); // After this, we can exit!
- int exit_code = OS_Web::get_singleton()->get_exit_code();
- memdelete(os);
- os = nullptr;
- emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing.
-}
-
-void early_cleanup_sync() {
- emscripten_set_main_loop(early_cleanup, -1, false);
+ shutdown_complete = true;
}
void main_loop_callback() {
@@ -87,7 +82,8 @@ void main_loop_callback() {
target_ticks += (uint64_t)(1000000 / max_fps);
}
if (os->main_loop_iterate()) {
- emscripten_cancel_main_loop(); // Cancel current loop and wait for cleanup_after_sync.
+ emscripten_cancel_main_loop(); // Cancel current loop and set the cleanup one.
+ emscripten_set_main_loop(exit_callback, -1, false);
godot_js_os_finish_async(cleanup_after_sync);
}
}
@@ -109,10 +105,14 @@ extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) {
}
os->set_exit_code(exit_code);
// Will only exit after sync.
- godot_js_os_finish_async(early_cleanup_sync);
+ emscripten_set_main_loop(exit_callback, -1, false);
+ godot_js_os_finish_async(cleanup_after_sync);
return exit_code;
}
+ os->set_exit_code(0);
+ main_started = true;
+
// Ease up compatibility.
ResourceLoader::set_abort_on_missing_resources(false);
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 7e412b140f..efbb47d965 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -19,19 +19,44 @@ common_win = [
"gl_manager_windows.cpp",
]
+common_win_wrap = [
+ "console_wrapper_windows.cpp",
+]
+
res_file = "godot_res.rc"
res_target = "godot_res" + env["OBJSUFFIX"]
res_obj = env.RES(res_target, res_file)
prog = env.add_program("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGSUFFIX"])
+# Build console wrapper app.
+if env["windows_subsystem"] == "gui":
+ env_wrap = env.Clone()
+ res_wrap_file = "godot_res_wrap.rc"
+ res_wrap_target = "godot_res_wrap" + env["OBJSUFFIX"]
+ res_wrap_obj = env_wrap.RES(res_wrap_target, res_wrap_file)
+
+ if env.msvc:
+ env_wrap.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
+ env_wrap.Append(LINKFLAGS=["version.lib"])
+ else:
+ env_wrap.Append(LINKFLAGS=["-Wl,--subsystem,console"])
+ env_wrap.Append(LIBS=["version"])
+
+ prog_wrap = env_wrap.add_program("#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"])
+
# Microsoft Visual Studio Project Generation
if env["vsproj"]:
env.vs_srcs += ["platform/windows/" + res_file]
env.vs_srcs += ["platform/windows/godot.natvis"]
for x in common_win:
env.vs_srcs += ["platform/windows/" + str(x)]
+ if env["windows_subsystem"] == "gui":
+ for x in common_win_wrap:
+ env.vs_srcs += ["platform/windows/" + str(x)]
if not os.getenv("VCINSTALLDIR"):
if env["debug_symbols"] and env["separate_debug_symbols"]:
env.AddPostAction(prog, run_in_subprocess(platform_windows_builders.make_debug_mingw))
+ if env["windows_subsystem"] == "gui":
+ env.AddPostAction(prog_wrap, run_in_subprocess(platform_windows_builders.make_debug_mingw))
diff --git a/platform/windows/console_wrapper_windows.cpp b/platform/windows/console_wrapper_windows.cpp
new file mode 100644
index 0000000000..258176426b
--- /dev/null
+++ b/platform/windows/console_wrapper_windows.cpp
@@ -0,0 +1,181 @@
+/*************************************************************************/
+/* console_wrapper_windows.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include <windows.h>
+
+#include <shlwapi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
+#endif
+
+int main(int argc, char *argv[]) {
+ // Get executable name.
+ WCHAR exe_name[MAX_PATH] = {};
+ if (!GetModuleFileNameW(nullptr, exe_name, MAX_PATH)) {
+ wprintf(L"GetModuleFileName failed, error %d\n", GetLastError());
+ return -1;
+ }
+
+ // Get product name from the resources and set console title.
+ DWORD ver_info_handle = 0;
+ DWORD ver_info_size = GetFileVersionInfoSizeW(exe_name, &ver_info_handle);
+ if (ver_info_size > 0) {
+ LPBYTE ver_info = (LPBYTE)malloc(ver_info_size);
+ if (ver_info) {
+ if (GetFileVersionInfoW(exe_name, ver_info_handle, ver_info_size, ver_info)) {
+ LPCWSTR text_ptr = nullptr;
+ UINT text_size = 0;
+ if (VerQueryValueW(ver_info, L"\\StringFileInfo\\040904b0\\ProductName", (void **)&text_ptr, &text_size) && (text_size > 0)) {
+ SetConsoleTitleW(text_ptr);
+ }
+ }
+ free(ver_info);
+ }
+ }
+
+ // Enable virtual terminal sequences processing.
+ HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD out_mode = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ SetConsoleMode(stdout_handle, out_mode);
+
+ // Find main executable name and check if it exist.
+ static PCWSTR exe_renames[] = {
+ L".console.exe",
+ L"_console.exe",
+ L" console.exe",
+ L"console.exe",
+ nullptr,
+ };
+
+ bool rename_found = false;
+ for (int i = 0; exe_renames[i]; i++) {
+ PWSTR c = StrRStrIW(exe_name, nullptr, exe_renames[i]);
+ if (c) {
+ CopyMemory(c, L".exe", sizeof(WCHAR) * 5);
+ rename_found = true;
+ break;
+ }
+ }
+ if (!rename_found) {
+ wprintf(L"Invalid wrapper executable name.\n");
+ return -1;
+ }
+
+ DWORD file_attrib = GetFileAttributesW(exe_name);
+ if (file_attrib == INVALID_FILE_ATTRIBUTES || (file_attrib & FILE_ATTRIBUTE_DIRECTORY)) {
+ wprintf(L"Main executable %ls not found.\n", exe_name);
+ return -1;
+ }
+
+ // Create job to monitor process tree.
+ HANDLE job_handle = CreateJobObjectW(nullptr, nullptr);
+ if (!job_handle) {
+ wprintf(L"CreateJobObject failed, error %d\n", GetLastError());
+ return -1;
+ }
+
+ HANDLE io_port_handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1);
+ if (!io_port_handle) {
+ wprintf(L"CreateIoCompletionPort failed, error %d\n", GetLastError());
+ return -1;
+ }
+
+ JOBOBJECT_ASSOCIATE_COMPLETION_PORT compl_port;
+ ZeroMemory(&compl_port, sizeof(compl_port));
+ compl_port.CompletionKey = job_handle;
+ compl_port.CompletionPort = io_port_handle;
+
+ if (!SetInformationJobObject(job_handle, JobObjectAssociateCompletionPortInformation, &compl_port, sizeof(compl_port))) {
+ wprintf(L"SetInformationJobObject(AssociateCompletionPortInformation) failed, error %d\n", GetLastError());
+ return -1;
+ }
+
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
+ ZeroMemory(&jeli, sizeof(jeli));
+ jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+ if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) {
+ wprintf(L"SetInformationJobObject(ExtendedLimitInformation) failed, error %d\n", GetLastError());
+ return -1;
+ }
+
+ // Start the main process.
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&pi, sizeof(pi));
+
+ STARTUPINFOW si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ WCHAR new_command_line[32767];
+ _snwprintf_s(new_command_line, 32767, _TRUNCATE, L"%ls %ls", exe_name, PathGetArgsW(GetCommandLineW()));
+
+ if (!CreateProcessW(nullptr, new_command_line, nullptr, nullptr, true, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi)) {
+ wprintf(L"CreateProcess failed, error %d\n", GetLastError());
+ return -1;
+ }
+
+ if (!AssignProcessToJobObject(job_handle, pi.hProcess)) {
+ wprintf(L"AssignProcessToJobObject failed, error %d\n", GetLastError());
+ return -1;
+ }
+
+ ResumeThread(pi.hThread);
+ CloseHandle(pi.hThread);
+
+ // Wait until main process and all of its children are finished.
+ DWORD completion_code = 0;
+ ULONG_PTR completion_key = 0;
+ LPOVERLAPPED overlapped = nullptr;
+
+ while (GetQueuedCompletionStatus(io_port_handle, &completion_code, &completion_key, &overlapped, INFINITE)) {
+ if ((HANDLE)completion_key == job_handle && completion_code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) {
+ break;
+ }
+ }
+
+ CloseHandle(job_handle);
+ CloseHandle(io_port_handle);
+
+ // Get exit code of the main process.
+ DWORD exit_code = 0;
+ GetExitCodeProcess(pi.hProcess, &exit_code);
+
+ CloseHandle(pi.hProcess);
+
+ return exit_code;
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
+ return main(0, nullptr);
+}
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 74868fc6a2..705e83dace 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -582,12 +582,14 @@ def configure_mingw(env):
]
)
- env.Append(CPPDEFINES=["VULKAN_ENABLED"])
- if not env["use_volk"]:
- env.Append(LIBS=["vulkan"])
+ if env["vulkan"]:
+ env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+ if not env["use_volk"]:
+ env.Append(LIBS=["vulkan"])
- env.Append(CPPDEFINES=["GLES3_ENABLED"])
- env.Append(LIBS=["opengl32"])
+ if env["opengl3"]:
+ env.Append(CPPDEFINES=["GLES3_ENABLED"])
+ env.Append(LIBS=["opengl32"])
env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index bc767a47e5..0b878feb7f 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -741,9 +741,20 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type,
case WINDOW_HANDLE: {
return (int64_t)windows[p_window].hWnd;
}
+#if defined(GLES3_ENABLED)
case WINDOW_VIEW: {
- return 0; // Not supported.
+ if (gl_manager) {
+ return (int64_t)gl_manager->get_hdc(p_window);
+ }
+ return 0;
}
+ case OPENGL_CONTEXT: {
+ if (gl_manager) {
+ return (int64_t)gl_manager->get_hglrc(p_window);
+ }
+ return 0;
+ }
+#endif
default: {
return 0;
}
@@ -1881,7 +1892,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
pos += sizeof(WORD);
f->seek(pos);
- icon_dir = (ICONDIR *)memrealloc(icon_dir, 3 * sizeof(WORD) + icon_dir->idCount * sizeof(ICONDIRENTRY));
+ icon_dir = (ICONDIR *)memrealloc(icon_dir, sizeof(ICONDIR) - sizeof(ICONDIRENTRY) + icon_dir->idCount * sizeof(ICONDIRENTRY));
f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY));
int small_icon_index = -1; // Select 16x16 with largest color count.
@@ -2012,6 +2023,12 @@ void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn
context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
}
#endif
+
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED);
+ }
+#endif
}
DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
@@ -2021,6 +2038,13 @@ DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_
return context_vulkan->get_vsync_mode(p_window);
}
#endif
+
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ return gl_manager->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
+ }
+#endif
+
return DisplayServer::VSYNC_ENABLED;
}
@@ -2444,10 +2468,16 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return 0; // Jump back.
}
case WM_MOUSELEAVE: {
- old_invalid = true;
- windows[window_id].mouse_outside = true;
+ if (window_mouseover_id == window_id) {
+ old_invalid = true;
+ window_mouseover_id = INVALID_WINDOW_ID;
- _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
+ } else if (window_mouseover_id != INVALID_WINDOW_ID) {
+ // This is reached during drag and drop, after dropping in a different window.
+ // Once-off notification, must call again.
+ track_mouse_leave_event(windows[window_mouseover_id].hWnd);
+ }
} break;
case WM_INPUT: {
@@ -2678,17 +2708,21 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
- if (windows[window_id].mouse_outside) {
+ if (window_mouseover_id != window_id) {
// Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
+ if (window_mouseover_id != INVALID_WINDOW_ID) {
+ // Leave previous window.
+ _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT);
+ }
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
}
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
cursor_set_shape(c);
- windows[window_id].mouse_outside = false;
+ window_mouseover_id = window_id;
// Once-off notification, must call again.
track_mouse_leave_event(hWnd);
@@ -2779,17 +2813,29 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
- if (windows[window_id].mouse_outside) {
+ DisplayServer::WindowID over_id = get_window_at_screen_position(mouse_get_position());
+ if (!Rect2(window_get_position(over_id), Point2(windows[over_id].width, windows[over_id].height)).has_point(mouse_get_position())) {
+ // Don't consider the windowborder as part of the window.
+ over_id = INVALID_WINDOW_ID;
+ }
+ if (window_mouseover_id != over_id) {
// Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
- _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ if (window_mouseover_id != INVALID_WINDOW_ID) {
+ // Leave previous window.
+ _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT);
+ }
+
+ if (over_id != INVALID_WINDOW_ID) {
+ _send_window_event(windows[over_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
}
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
cursor_set_shape(c);
- windows[window_id].mouse_outside = false;
+ window_mouseover_id = over_id;
// Once-off notification, must call again.
track_mouse_leave_event(hWnd);
@@ -2800,9 +2846,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
break;
}
+ DisplayServer::WindowID receiving_window_id = _get_focused_window_or_popup();
+ if (receiving_window_id == INVALID_WINDOW_ID) {
+ receiving_window_id = window_id;
+ }
Ref<InputEventMouseMotion> mm;
mm.instantiate();
- mm->set_window_id(window_id);
+ mm->set_window_id(receiving_window_id);
mm->set_ctrl_pressed((wParam & MK_CONTROL) != 0);
mm->set_shift_pressed((wParam & MK_SHIFT) != 0);
mm->set_alt_pressed(alt_mem);
@@ -2859,9 +2909,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
old_x = mm->get_position().x;
old_y = mm->get_position().y;
- if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) {
- Input::get_singleton()->parse_input_event(mm);
+
+ if (!windows[receiving_window_id].window_has_focus) {
+ // In case of unfocused Popups, adjust event position.
+ Point2i pos = mm->get_position() - window_get_position(receiving_window_id) + window_get_position(window_id);
+ mm->set_position(pos);
+ mm->set_global_position(pos);
}
+ Input::get_singleton()->parse_input_event(mm);
} break;
case WM_LBUTTONDOWN:
@@ -3559,6 +3614,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
windows.erase(id);
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
}
+ window_set_vsync_mode(p_vsync_mode, id);
}
#endif
@@ -3704,7 +3760,7 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) {
}
}
-DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
drop_events = false;
key_event_pos = 0;
@@ -3856,6 +3912,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
+ if (p_position != nullptr) {
+ window_position = *p_position;
+ }
+
WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution));
ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
@@ -3919,12 +3979,24 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerWindows::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, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
- "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
- "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_name = OS::get_singleton()->get_executable_path().get_file();
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'./" +
+ executable_name + " --rendering-driver opengl3'.\n "
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 53cde001ae..8ac0086d69 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -323,6 +323,8 @@ class DisplayServerWindows : public DisplayServer {
LPARAM lParam;
};
+ WindowID window_mouseover_id = INVALID_WINDOW_ID;
+
KeyEvent key_event_buffer[KEY_EVENT_BUFFER_SIZE];
int key_event_pos;
@@ -398,7 +400,6 @@ class DisplayServerWindows : public DisplayServer {
Size2 window_rect;
Point2 last_pos;
- bool mouse_outside = true;
ObjectID instance_id;
@@ -623,11 +624,11 @@ public:
virtual void set_context(Context p_context) override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *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, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_windows_driver();
- DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerWindows();
};
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 016d201f2c..f04177d79a 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -31,34 +31,138 @@
#include "export_plugin.h"
#include "core/config/project_settings.h"
+#include "core/io/image_loader.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
-Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
- if (p_preset->get("codesign/enable")) {
- return _code_sign(p_preset, p_path);
+Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) {
+ static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ };
+
+ struct IconData {
+ Vector<uint8_t> data;
+ uint8_t pal_colors = 0;
+ uint16_t planes = 0;
+ uint16_t bpp = 32;
+ };
+
+ HashMap<uint8_t, IconData> images;
+ Error err;
+
+ if (p_src_path.get_extension() == "ico") {
+ Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err);
+ if (err != OK) {
+ return err;
+ }
+
+ // Read ICONDIR.
+ f->get_16(); // Reserved.
+ uint16_t icon_type = f->get_16(); // Image type: 1 - ICO.
+ uint16_t icon_count = f->get_16(); // Number of images.
+ ERR_FAIL_COND_V(icon_type != 1, ERR_CANT_OPEN);
+
+ for (uint16_t i = 0; i < icon_count; i++) {
+ // Read ICONDIRENTRY.
+ uint16_t w = f->get_8(); // Width in pixels.
+ uint16_t h = f->get_8(); // Height in pixels.
+ uint8_t pal_colors = f->get_8(); // Number of colors in the palette (0 - no palette).
+ f->get_8(); // Reserved.
+ uint16_t planes = f->get_16(); // Number of color planes.
+ uint16_t bpp = f->get_16(); // Bits per pixel.
+ uint32_t img_size = f->get_32(); // Image data size in bytes.
+ uint32_t img_offset = f->get_32(); // Image data offset.
+ if (w != h) {
+ continue;
+ }
+
+ // Read image data.
+ uint64_t prev_offset = f->get_position();
+ images[w].pal_colors = pal_colors;
+ images[w].planes = planes;
+ images[w].bpp = bpp;
+ images[w].data.resize(img_size);
+ f->seek(img_offset);
+ f->get_buffer(images[w].data.ptrw(), img_size);
+ f->seek(prev_offset);
+ }
} else {
- return OK;
+ Ref<Image> src_image;
+ src_image.instantiate();
+ err = ImageLoader::load_image(p_src_path, src_image);
+ ERR_FAIL_COND_V(err != OK || src_image->is_empty(), ERR_CANT_OPEN);
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ int size = (icon_size[i] == 0) ? 256 : icon_size[i];
+
+ Ref<Image> res_image = src_image->duplicate();
+ ERR_FAIL_COND_V(res_image.is_null() || res_image->is_empty(), ERR_CANT_OPEN);
+ res_image->resize(size, size, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
+ images[icon_size[i]].data = res_image->save_png_to_buffer();
+ }
}
-}
-Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
- Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
- if (f.is_null()) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path));
- return ERR_CANT_CREATE;
+ uint16_t valid_icon_count = 0;
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ valid_icon_count++;
+ } else {
+ int size = (icon_size[i] == 0) ? 256 : icon_size[i];
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Icon size \"%d\" is missing."), size));
+ }
}
+ ERR_FAIL_COND_V(valid_icon_count == 0, ERR_CANT_OPEN);
- f->store_line("@echo off");
- f->store_line("title \"" + p_app_name + "\"");
- f->store_line("\"%~dp0" + p_pkg_name + "\" \"%*\"");
- f->store_line("pause > nul");
+ Ref<FileAccess> fw = FileAccess::open(p_dst_path, FileAccess::WRITE, &err);
+ if (err != OK) {
+ return err;
+ }
+ // Write ICONDIR.
+ fw->store_16(0); // Reserved.
+ fw->store_16(1); // Image type: 1 - ICO.
+ fw->store_16(valid_icon_count); // Number of images.
+
+ // Write ICONDIRENTRY.
+ uint32_t img_offset = 6 + 16 * valid_icon_count;
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ const IconData &di = images[icon_size[i]];
+ fw->store_8(icon_size[i]); // Width in pixels.
+ fw->store_8(icon_size[i]); // Height in pixels.
+ fw->store_8(di.pal_colors); // Number of colors in the palette (0 - no palette).
+ fw->store_8(0); // Reserved.
+ fw->store_16(di.planes); // Number of color planes.
+ fw->store_16(di.bpp); // Bits per pixel.
+ fw->store_32(di.data.size()); // Image data size in bytes.
+ fw->store_32(img_offset); // Image data offset.
+
+ img_offset += di.data.size();
+ }
+ }
+
+ // Write image data.
+ for (size_t i = 0; i < sizeof(icon_size) / sizeof(icon_size[0]); ++i) {
+ if (images.has(icon_size[i])) {
+ const IconData &di = images[icon_size[i]];
+ fw->store_buffer(di.data.ptr(), di.data.size());
+ }
+ }
return OK;
}
+Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
+ if (p_preset->get("codesign/enable")) {
+ return _code_sign(p_preset, p_path);
+ } else {
+ return OK;
+ }
+}
+
Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
if (p_preset->get("application/modify_resources")) {
- _rcedit_add_data(p_preset, p_path);
+ _rcedit_add_data(p_preset, p_path, true);
+ String wrapper_path = p_path.get_basename() + ".console.exe";
+ if (FileAccess::exists(wrapper_path)) {
+ _rcedit_add_data(p_preset, wrapper_path, false);
+ }
}
return OK;
}
@@ -71,6 +175,10 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
if (p_preset->get("codesign/enable") && err == OK) {
_code_sign(p_preset, pck_path);
+ String wrapper_path = p_path.get_basename() + ".console.exe";
+ if (FileAccess::exists(wrapper_path)) {
+ _code_sign(p_preset, wrapper_path);
+ }
}
if (p_preset->get("binary_format/embed_pck") && err == OK) {
@@ -81,25 +189,6 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
}
- String app_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- app_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
- } else {
- app_name = "Unnamed";
- }
- app_name = OS::get_singleton()->get_safe_dir_name(app_name);
-
- // Save console script.
- if (err == OK) {
- int con_scr = p_preset->get("debug/export_console_script");
- if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
- String scr_path = p_path.get_basename() + ".cmd";
- if (_export_debug_script(p_preset, app_name, p_path.get_file(), scr_path) != OK) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), TTR("Could not create console script."));
- }
- }
- }
-
return err;
}
@@ -136,7 +225,9 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico.*.png,*.webp,*.svg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
@@ -146,8 +237,8 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
}
-Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
- String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
+Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) {
+ String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (rcedit_path != String() && !FileAccess::exists(rcedit_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find rcedit executable at \"%s\"."), rcedit_path));
@@ -160,7 +251,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
#ifndef WINDOWS_ENABLED
// On non-Windows we need WINE to run rcedit
- String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
+ String wine_path = EDITOR_GET("export/windows/wine");
if (!wine_path.is_empty() && !FileAccess::exists(wine_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find wine executable at \"%s\"."), wine_path));
@@ -173,6 +264,21 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
#endif
String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
+ if (p_console_icon) {
+ String console_icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/console_wrapper_icon"));
+ if (!console_icon_path.is_empty() && FileAccess::exists(console_icon_path)) {
+ icon_path = console_icon_path;
+ }
+ }
+
+ String tmp_icon_path = EditorPaths::get_singleton()->get_cache_dir().path_join("_rcedit.ico");
+ if (!icon_path.is_empty()) {
+ if (_process_icon(p_preset, icon_path, tmp_icon_path) != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Invalid icon file \"%s\"."), icon_path));
+ icon_path = String();
+ }
+ }
+
String file_verion = p_preset->get("application/file_version");
String product_version = p_preset->get("application/product_version");
String company_name = p_preset->get("application/company_name");
@@ -186,7 +292,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
args.push_back(p_path);
if (!icon_path.is_empty()) {
args.push_back("--set-icon");
- args.push_back(icon_path);
+ args.push_back(tmp_icon_path);
}
if (!file_verion.is_empty()) {
args.push_back("--set-file-version");
@@ -230,6 +336,11 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String str;
Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true);
+
+ if (FileAccess::exists(tmp_icon_path)) {
+ DirAccess::remove_file_or_error(tmp_icon_path);
+ }
+
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset."));
return err;
@@ -248,7 +359,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
List<String> args;
#ifdef WINDOWS_ENABLED
- String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
+ String signtool_path = EDITOR_GET("export/windows/signtool");
if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find signtool executable at \"%s\"."), signtool_path));
return ERR_FILE_NOT_FOUND;
@@ -257,7 +368,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
signtool_path = "signtool"; // try to run signtool from PATH
}
#else
- String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
+ String signtool_path = EDITOR_GET("export/windows/osslsigncode");
if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find osslsigncode executable at \"%s\"."), signtool_path));
return ERR_FILE_NOT_FOUND;
@@ -420,7 +531,7 @@ bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<Edito
String err = "";
bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates);
- String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
+ String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) {
err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > rcedit) to change the icon or app information data.") + "\n";
}
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index f85331c898..a9e6d51b9d 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -38,9 +38,9 @@
#include "platform/windows/logo.gen.h"
class EditorExportPlatformWindows : public EditorExportPlatformPC {
- Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+ Error _process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path);
+ Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
- Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
public:
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp
index 7689751f1b..5b39c56ea3 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows.cpp
@@ -185,6 +185,10 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
return ERR_CANT_CREATE;
}
+ if (!wglSwapIntervalEXT) {
+ wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+ }
+
return OK;
}
@@ -293,50 +297,40 @@ void GLManager_Windows::swap_buffers() {
}
Error GLManager_Windows::initialize() {
- wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
- wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
- //glWrapperInit(wrapper_get_proc_address);
-
return OK;
}
-void GLManager_Windows::set_use_vsync(bool p_use) {
- /*
- static bool setup = false;
- static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr;
- static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr;
- static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr;
-
- if (!setup) {
- setup = true;
- String extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
- if (extensions.find("GLX_EXT_swap_control") != -1) {
- glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT");
- }
- if (extensions.find("GLX_MESA_swap_control") != -1) {
- glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA");
- }
- if (extensions.find("GLX_SGI_swap_control") != -1) {
- glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI");
- }
+void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use) {
+ GLWindow &win = get_window(p_window_id);
+ GLWindow *current = _current_window;
+
+ if (&win != _current_window) {
+ window_make_current(p_window_id);
}
- int val = p_use ? 1 : 0;
- if (glXSwapIntervalMESA) {
- glXSwapIntervalMESA(val);
- } else if (glXSwapIntervalSGI) {
- glXSwapIntervalSGI(val);
- } else if (glXSwapIntervalEXT) {
- GLXDrawable drawable = glXGetCurrentDrawable();
- glXSwapIntervalEXT(x11_display, drawable, val);
- } else {
- return;
+
+ if (wglSwapIntervalEXT) {
+ win.use_vsync = p_use;
+ wglSwapIntervalEXT(p_use ? 1 : 0);
}
- use_vsync = p_use;
- */
+
+ if (current != _current_window) {
+ _current_window = current;
+ make_current();
+ }
+}
+
+bool GLManager_Windows::is_using_vsync(DisplayServer::WindowID p_window_id) const {
+ return get_window(p_window_id).use_vsync;
}
-bool GLManager_Windows::is_using_vsync() const {
- return use_vsync;
+HDC GLManager_Windows::get_hdc(DisplayServer::WindowID p_window_id) {
+ return get_window(p_window_id).hDC;
+}
+
+HGLRC GLManager_Windows::get_hglrc(DisplayServer::WindowID p_window_id) {
+ const GLWindow &win = get_window(p_window_id);
+ const GLDisplay &disp = get_display(win.gldisplay_id);
+ return disp.hRC;
}
GLManager_Windows::GLManager_Windows(ContextType p_context_type) {
@@ -344,7 +338,6 @@ GLManager_Windows::GLManager_Windows(ContextType p_context_type) {
direct_render = false;
glx_minor = glx_major = 0;
- use_vsync = false;
_current_window = nullptr;
}
diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows.h
index 5e43a3de2a..94f3ce9860 100644
--- a/platform/windows/gl_manager_windows.h
+++ b/platform/windows/gl_manager_windows.h
@@ -54,6 +54,7 @@ private:
struct GLWindow {
int width = 0;
int height = 0;
+ bool use_vsync = false;
// windows specific
HDC hDC;
@@ -72,8 +73,8 @@ private:
GLWindow *_current_window = nullptr;
- PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
- PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
+ PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr;
+ PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr;
// funcs
void _internal_set_current_window(GLWindow *p_win);
@@ -86,7 +87,6 @@ private:
bool direct_render;
int glx_minor, glx_major;
- bool use_vsync;
ContextType context_type;
private:
@@ -110,8 +110,11 @@ public:
Error initialize();
- void set_use_vsync(bool p_use);
- bool is_using_vsync() const;
+ void set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use);
+ bool is_using_vsync(DisplayServer::WindowID p_window_id) const;
+
+ HDC get_hdc(DisplayServer::WindowID p_window_id);
+ HGLRC get_hglrc(DisplayServer::WindowID p_window_id);
GLManager_Windows(ContextType p_context_type);
~GLManager_Windows();
diff --git a/platform/windows/godot_res_wrap.rc b/platform/windows/godot_res_wrap.rc
new file mode 100644
index 0000000000..9877ff6075
--- /dev/null
+++ b/platform/windows/godot_res_wrap.rc
@@ -0,0 +1,33 @@
+#include "core/version.h"
+#ifndef _STR
+#define _STR(m_x) #m_x
+#define _MKSTR(m_x) _STR(m_x)
+#endif
+
+GODOT_ICON ICON platform/windows/godot.ico
+
+1 VERSIONINFO
+FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+FILEOS 4
+FILETYPE 1
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Godot Engine"
+ VALUE "FileDescription", VERSION_NAME " (Console)"
+ VALUE "FileVersion", VERSION_NUMBER
+ VALUE "ProductName", VERSION_NAME " (Console)"
+ VALUE "Licence", "MIT"
+ VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur and contributors"
+ VALUE "Info", "https://godotengine.org"
+ VALUE "ProductVersion", VERSION_FULL_BUILD
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index d039fd13a7..2b5c8cad48 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -167,7 +167,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
const GUID &guid = instance->guidProduct;
char uid[128];
- ERR_FAIL_COND_V_MSG(memcmp(&guid.Data4[2], "PIDVID", 6), false, "DirectInput device not recognised.");
+ ERR_FAIL_COND_V_MSG(memcmp(&guid.Data4[2], "PIDVID", 6), false, "DirectInput device not recognized.");
WORD type = BSWAP16(0x03);
WORD vendor = BSWAP16(LOWORD(guid.Data1));
WORD product = BSWAP16(HIWORD(guid.Data1));
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 5ca064e523..d8548eb545 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -103,8 +103,6 @@ void RedirectIOToConsole() {
RedirectStream("CONIN$", "r", stdin, STD_INPUT_HANDLE);
RedirectStream("CONOUT$", "w", stdout, STD_OUTPUT_HANDLE);
RedirectStream("CONOUT$", "w", stderr, STD_ERROR_HANDLE);
-
- printf("\n"); // Make sure our output is starting from the new line.
}
}
@@ -311,6 +309,10 @@ String OS_Windows::get_version() const {
}
Vector<String> OS_Windows::get_video_adapter_driver_info() const {
+ if (RenderingServer::get_singleton()->get_rendering_device() == nullptr) {
+ return Vector<String>();
+ }
+
REFCLSID clsid = CLSID_WbemLocator; // Unmarshaler CLSID
REFIID uuid = IID_IWbemLocator; // Interface UUID
IWbemLocator *wbemLocator = NULL; // to get the services
@@ -847,7 +849,19 @@ String OS_Windows::get_system_font_path(const String &p_font_name, bool p_bold,
if (FAILED(hr)) {
continue;
}
- return String::utf16((const char16_t *)&file_path[0]);
+ String fpath = String::utf16((const char16_t *)&file_path[0]);
+
+ WIN32_FIND_DATAW d;
+ HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d);
+ if (fnd != INVALID_HANDLE_VALUE) {
+ String fname = String::utf16((const char16_t *)d.cFileName);
+ if (!fname.is_empty()) {
+ fpath = fpath.get_base_dir().path_join(fname);
+ }
+ FindClose(fnd);
+ }
+
+ return fpath;
}
return String();
}
@@ -1153,11 +1167,11 @@ String OS_Windows::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
}
String OS_Windows::get_user_data_dir() const {
- String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name"));
+ String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
if (!appname.is_empty()) {
- bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir");
+ bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
if (use_custom_dir) {
- String custom_dir = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/custom_user_dir_name"), true);
+ String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
if (custom_dir.is_empty()) {
custom_dir = appname;
}
@@ -1177,7 +1191,14 @@ String OS_Windows::get_unique_id() const {
}
bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc";
+ if (p_feature == "system_fonts") {
+ return true;
+ }
+ if (p_feature == "pc") {
+ return true;
+ }
+
+ return false;
}
void OS_Windows::disable_crash_handler() {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index bf934bce64..6f89be699a 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -63,6 +63,10 @@
#define WINDOWS_DEBUG_OUTPUT_ENABLED
#endif
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
+#endif
+
template <class T>
class ComAutoreleaseRef {
public:
diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h
index 8e80f8cacb..7f0042d76f 100644
--- a/platform/windows/platform_config.h
+++ b/platform/windows/platform_config.h
@@ -30,4 +30,4 @@
#include <malloc.h>
-#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h"
+#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h"
diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h
index 2ecdfc8f3f..9dedcabb2b 100644
--- a/platform/windows/vulkan_context_win.h
+++ b/platform/windows/vulkan_context_win.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_WIN_H
#define VULKAN_CONTEXT_WIN_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
#define WIN32_LEAN_AND_MEAN
@@ -46,4 +48,6 @@ public:
~VulkanContextWindows();
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_WIN_H