summaryrefslogtreecommitdiffstats
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/SCsub1
-rw-r--r--platform/android/SCsub1
-rw-r--r--platform/android/api/api.cpp10
-rw-r--r--platform/android/api/java_class_wrapper.h15
-rw-r--r--platform/android/api/jni_singleton.h197
-rw-r--r--platform/android/display_server_android.cpp7
-rw-r--r--platform/android/display_server_android.h1
-rw-r--r--platform/android/doc_classes/EditorExportPlatformAndroid.xml3
-rw-r--r--platform/android/export/export_plugin.cpp45
-rw-r--r--platform/android/export/export_plugin.h5
-rw-r--r--platform/android/java/app/build.gradle6
-rw-r--r--platform/android/java/app/config.gradle5
-rw-r--r--platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotEditor.kt4
-rw-r--r--platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotXRGame.kt2
-rw-r--r--platform/android/java/lib/res/mipmap-anydpi-v26/icon.xml1
-rw-r--r--platform/android/java/lib/res/mipmap/icon_monochrome.pngbin0 -> 5617 bytes
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.kt6
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotIO.java8
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/AndroidRuntimePlugin.kt63
-rw-r--r--platform/android/java_class_wrapper.cpp10
-rw-r--r--platform/android/java_godot_io_wrapper.cpp11
-rw-r--r--platform/android/java_godot_io_wrapper.h2
-rw-r--r--platform/android/java_godot_lib_jni.cpp4
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp25
-rw-r--r--platform/android/rendering_context_driver_vulkan_android.cpp6
-rw-r--r--platform/ios/SCsub1
-rw-r--r--platform/ios/detect.py4
-rw-r--r--platform/ios/display_server_ios.h7
-rw-r--r--platform/ios/display_server_ios.mm10
-rw-r--r--platform/ios/doc_classes/EditorExportPlatformIOS.xml125
-rw-r--r--platform/ios/export/export_plugin.cpp233
-rw-r--r--platform/ios/os_ios.mm6
-rw-r--r--platform/linuxbsd/SCsub1
-rw-r--r--platform/linuxbsd/detect.py4
-rw-r--r--platform/linuxbsd/wayland/SCsub1
-rw-r--r--platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp6
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.h4
-rw-r--r--platform/linuxbsd/x11/SCsub1
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp12
-rw-r--r--platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp6
-rw-r--r--platform/macos/SCsub1
-rw-r--r--platform/macos/detect.py12
-rw-r--r--platform/macos/display_server_macos.mm10
-rw-r--r--platform/macos/godot_menu_delegate.mm6
-rw-r--r--platform/web/SCsub1
-rw-r--r--platform/web/detect.py29
-rw-r--r--platform/web/export/export_plugin.cpp8
-rw-r--r--platform/web/js/libs/library_godot_audio.js38
-rw-r--r--platform/windows/SCsub1
-rw-r--r--platform/windows/detect.py25
-rw-r--r--platform/windows/display_server_windows.cpp39
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--platform/windows/gl_manager_windows_native.cpp4
-rw-r--r--platform/windows/rendering_context_driver_vulkan_windows.cpp6
55 files changed, 633 insertions, 412 deletions
diff --git a/platform/SCsub b/platform/SCsub
index cdaa6074ba..7c9d07f6ef 100644
--- a/platform/SCsub
+++ b/platform/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
from glob import glob
from pathlib import Path
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 8c88b419b3..3bc8959351 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
import subprocess
import sys
diff --git a/platform/android/api/api.cpp b/platform/android/api/api.cpp
index 6920f801e5..078b9ab748 100644
--- a/platform/android/api/api.cpp
+++ b/platform/android/api/api.cpp
@@ -41,13 +41,11 @@ static JavaClassWrapper *java_class_wrapper = nullptr;
void register_android_api() {
#if !defined(ANDROID_ENABLED)
- // On Android platforms, the `java_class_wrapper` instantiation and the
- // `JNISingleton` registration occurs in
+ // On Android platforms, the `java_class_wrapper` instantiation occurs in
// `platform/android/java_godot_lib_jni.cpp#Java_org_godotengine_godot_GodotLib_setup`
- java_class_wrapper = memnew(JavaClassWrapper); // Dummy
- GDREGISTER_CLASS(JNISingleton);
+ java_class_wrapper = memnew(JavaClassWrapper);
#endif
-
+ GDREGISTER_CLASS(JNISingleton);
GDREGISTER_CLASS(JavaClass);
GDREGISTER_CLASS(JavaObject);
GDREGISTER_CLASS(JavaClassWrapper);
@@ -108,7 +106,7 @@ Ref<JavaClass> JavaObject::get_java_class() const {
JavaClassWrapper *JavaClassWrapper::singleton = nullptr;
-Ref<JavaClass> JavaClassWrapper::wrap(const String &) {
+Ref<JavaClass> JavaClassWrapper::_wrap(const String &, bool) {
return Ref<JavaClass>();
}
diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h
index 52df1644be..c74cef8dd0 100644
--- a/platform/android/api/java_class_wrapper.h
+++ b/platform/android/api/java_class_wrapper.h
@@ -47,7 +47,7 @@ class JavaClass : public RefCounted {
GDCLASS(JavaClass, RefCounted);
#ifdef ANDROID_ENABLED
- enum ArgumentType{
+ enum ArgumentType {
ARG_TYPE_VOID,
ARG_TYPE_BOOLEAN,
ARG_TYPE_BYTE,
@@ -262,6 +262,8 @@ class JavaClassWrapper : public Object {
bool _get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig);
#endif
+ Ref<JavaClass> _wrap(const String &p_class, bool p_allow_private_methods_access);
+
static JavaClassWrapper *singleton;
protected:
@@ -270,15 +272,14 @@ protected:
public:
static JavaClassWrapper *get_singleton() { return singleton; }
- Ref<JavaClass> wrap(const String &p_class);
+ Ref<JavaClass> wrap(const String &p_class) {
+ return _wrap(p_class, false);
+ }
#ifdef ANDROID_ENABLED
- Ref<JavaClass> wrap_jclass(jclass p_class);
-
- JavaClassWrapper(jobject p_activity = nullptr);
-#else
- JavaClassWrapper();
+ Ref<JavaClass> wrap_jclass(jclass p_class, bool p_allow_private_methods_access = false);
#endif
+ JavaClassWrapper();
};
#endif // JAVA_CLASS_WRAPPER_H
diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h
index 06afc4eb78..5e940819bc 100644
--- a/platform/android/api/jni_singleton.h
+++ b/platform/android/api/jni_singleton.h
@@ -31,193 +31,53 @@
#ifndef JNI_SINGLETON_H
#define JNI_SINGLETON_H
+#include "java_class_wrapper.h"
+
#include "core/config/engine.h"
#include "core/variant/variant.h"
-#ifdef ANDROID_ENABLED
-#include "jni_utils.h"
-#endif
-
class JNISingleton : public Object {
GDCLASS(JNISingleton, Object);
-#ifdef ANDROID_ENABLED
struct MethodData {
- jmethodID method;
Variant::Type ret_type;
Vector<Variant::Type> argtypes;
};
- jobject instance;
RBMap<StringName, MethodData> method_map;
-#endif
+ Ref<JavaObject> wrapped_object;
public:
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override {
-#ifdef ANDROID_ENABLED
- RBMap<StringName, MethodData>::Element *E = method_map.find(p_method);
-
- // Check the method we're looking for is in the JNISingleton map and that
- // the arguments match.
- bool call_error = !E || E->get().argtypes.size() != p_argcount;
- if (!call_error) {
- for (int i = 0; i < p_argcount; i++) {
- if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
- call_error = true;
- break;
+ if (wrapped_object.is_valid()) {
+ RBMap<StringName, MethodData>::Element *E = method_map.find(p_method);
+
+ // Check the method we're looking for is in the JNISingleton map and that
+ // the arguments match.
+ bool call_error = !E || E->get().argtypes.size() != p_argcount;
+ if (!call_error) {
+ for (int i = 0; i < p_argcount; i++) {
+ if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
+ call_error = true;
+ break;
+ }
}
}
- }
-
- if (call_error) {
- // The method is not in this map, defaulting to the regular instance calls.
- return Object::callp(p_method, p_args, p_argcount, r_error);
- }
-
- ERR_FAIL_NULL_V(instance, Variant());
-
- r_error.error = Callable::CallError::CALL_OK;
-
- jvalue *v = nullptr;
- if (p_argcount) {
- v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
- }
-
- JNIEnv *env = get_jni_env();
-
- int res = env->PushLocalFrame(16);
-
- ERR_FAIL_COND_V(res != 0, Variant());
-
- List<jobject> to_erase;
- for (int i = 0; i < p_argcount; i++) {
- jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
- v[i] = vr.val;
- if (vr.obj) {
- to_erase.push_back(vr.obj);
+ if (!call_error) {
+ return wrapped_object->callp(p_method, p_args, p_argcount, r_error);
}
}
- Variant ret;
-
- switch (E->get().ret_type) {
- case Variant::NIL: {
- env->CallVoidMethodA(instance, E->get().method, v);
- } break;
- case Variant::BOOL: {
- ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
- } break;
- case Variant::INT: {
- ret = env->CallIntMethodA(instance, E->get().method, v);
- } break;
- case Variant::FLOAT: {
- ret = env->CallFloatMethodA(instance, E->get().method, v);
- } break;
- case Variant::STRING: {
- jobject o = env->CallObjectMethodA(instance, E->get().method, v);
- ret = jstring_to_string((jstring)o, env);
- env->DeleteLocalRef(o);
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- ret = _jobject_to_variant(env, arr);
-
- env->DeleteLocalRef(arr);
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- Vector<int> sarr;
- sarr.resize(fCount);
-
- int *w = sarr.ptrw();
- env->GetIntArrayRegion(arr, 0, fCount, w);
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
- case Variant::PACKED_INT64_ARRAY: {
- jlongArray arr = (jlongArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- Vector<int64_t> sarr;
- sarr.resize(fCount);
-
- int64_t *w = sarr.ptrw();
- env->GetLongArrayRegion(arr, 0, fCount, w);
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- Vector<float> sarr;
- sarr.resize(fCount);
-
- float *w = sarr.ptrw();
- env->GetFloatArrayRegion(arr, 0, fCount, w);
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
- case Variant::PACKED_FLOAT64_ARRAY: {
- jdoubleArray arr = (jdoubleArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- Vector<double> sarr;
- sarr.resize(fCount);
-
- double *w = sarr.ptrw();
- env->GetDoubleArrayRegion(arr, 0, fCount, w);
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
- case Variant::DICTIONARY: {
- jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
- ret = _jobject_to_variant(env, obj);
- env->DeleteLocalRef(obj);
-
- } break;
- case Variant::OBJECT: {
- jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
- ret = _jobject_to_variant(env, obj);
- env->DeleteLocalRef(obj);
- } break;
- default: {
- env->PopLocalFrame(nullptr);
- ERR_FAIL_V(Variant());
- } break;
- }
-
- while (to_erase.size()) {
- env->DeleteLocalRef(to_erase.front()->get());
- to_erase.pop_front();
- }
-
- env->PopLocalFrame(nullptr);
-
- return ret;
-#else // ANDROID_ENABLED
-
- // Defaulting to the regular instance calls.
return Object::callp(p_method, p_args, p_argcount, r_error);
-#endif
}
-#ifdef ANDROID_ENABLED
- jobject get_instance() const {
- return instance;
+ Ref<JavaObject> get_wrapped_object() const {
+ return wrapped_object;
}
- void set_instance(jobject p_instance) {
- instance = p_instance;
- }
-
- void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
+ void add_method(const StringName &p_name, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
MethodData md;
- md.method = p_method;
md.argtypes = p_args;
md.ret_type = p_ret_type;
method_map[p_name] = md;
@@ -232,24 +92,15 @@ public:
ADD_SIGNAL(mi);
}
-#endif
+ JNISingleton() {}
- JNISingleton() {
-#ifdef ANDROID_ENABLED
- instance = nullptr;
-#endif
+ JNISingleton(const Ref<JavaObject> &p_wrapped_object) {
+ wrapped_object = p_wrapped_object;
}
~JNISingleton() {
-#ifdef ANDROID_ENABLED
method_map.clear();
- if (instance) {
- JNIEnv *env = get_jni_env();
- ERR_FAIL_NULL(env);
-
- env->DeleteGlobalRef(instance);
- }
-#endif
+ wrapped_object.unref();
}
};
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index c1053215c6..fa5b970a96 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -304,6 +304,13 @@ int DisplayServerAndroid::virtual_keyboard_get_height() const {
return godot_io_java->get_vk_height();
}
+bool DisplayServerAndroid::has_hardware_keyboard() const {
+ GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
+ ERR_FAIL_NULL_V(godot_io_java, false);
+
+ return godot_io_java->has_hardware_keyboard();
+}
+
void DisplayServerAndroid::window_set_window_event_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
window_event_callback = p_callable;
}
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 90bda18cfa..65c6a53446 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -138,6 +138,7 @@ public:
virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
virtual void virtual_keyboard_hide() override;
virtual int virtual_keyboard_get_height() const override;
+ virtual bool has_hardware_keyboard() const override;
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
index 020e432155..2fe5539e56 100644
--- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml
+++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
@@ -102,6 +102,9 @@
<member name="launcher_icons/adaptive_foreground_432x432" type="String" setter="" getter="">
Foreground layer of the application adaptive icon file. See [url=https://developer.android.com/develop/ui/views/launch/icon_design_adaptive#design-adaptive-icons]Design adaptive icons[/url].
</member>
+ <member name="launcher_icons/adaptive_monochrome_432x432" type="String" setter="" getter="">
+ Monochrome layer of the application adaptive icon file. See [url=https://developer.android.com/develop/ui/views/launch/icon_design_adaptive#design-adaptive-icons]Design adaptive icons[/url].
+ </member>
<member name="launcher_icons/main_192x192" type="String" setter="" getter="">
Application icon file. If left empty, it will fallback to [member ProjectSettings.application/config/icon].
</member>
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index e3d9807af7..41f460ca8f 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -222,6 +222,7 @@ static const int icon_densities_count = 6;
static const char *launcher_icon_option = PNAME("launcher_icons/main_192x192");
static const char *launcher_adaptive_icon_foreground_option = PNAME("launcher_icons/adaptive_foreground_432x432");
static const char *launcher_adaptive_icon_background_option = PNAME("launcher_icons/adaptive_background_432x432");
+static const char *launcher_adaptive_icon_monochrome_option = PNAME("launcher_icons/adaptive_monochrome_432x432");
static const LauncherIcon launcher_icons[icon_densities_count] = {
{ "res/mipmap-xxxhdpi-v4/icon.png", 192 },
@@ -250,6 +251,15 @@ static const LauncherIcon launcher_adaptive_icon_backgrounds[icon_densities_coun
{ "res/mipmap/icon_background.png", 432 }
};
+static const LauncherIcon launcher_adaptive_icon_monochromes[icon_densities_count] = {
+ { "res/mipmap-xxxhdpi-v4/icon_monochrome.png", 432 },
+ { "res/mipmap-xxhdpi-v4/icon_monochrome.png", 324 },
+ { "res/mipmap-xhdpi-v4/icon_monochrome.png", 216 },
+ { "res/mipmap-hdpi-v4/icon_monochrome.png", 162 },
+ { "res/mipmap-mdpi-v4/icon_monochrome.png", 108 },
+ { "res/mipmap/icon_monochrome.png", 432 }
+};
+
static const int EXPORT_FORMAT_APK = 0;
static const int EXPORT_FORMAT_AAB = 1;
@@ -1644,12 +1654,13 @@ void EditorExportPlatformAndroid::_process_launcher_icons(const String &p_file_n
}
}
-void EditorExportPlatformAndroid::load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) {
+void EditorExportPlatformAndroid::load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background, Ref<Image> &monochrome) {
String project_icon_path = GLOBAL_GET("application/config/icon");
icon.instantiate();
foreground.instantiate();
background.instantiate();
+ monochrome.instantiate();
// Regular icon: user selection -> project icon -> default.
String path = static_cast<String>(p_preset->get(launcher_icon_option)).strip_edges();
@@ -1677,12 +1688,20 @@ void EditorExportPlatformAndroid::load_icon_refs(const Ref<EditorExportPreset> &
print_verbose("Loading adaptive background icon from " + path);
ImageLoader::load_image(path, background);
}
+
+ // Adaptive monochrome: user selection -> default.
+ path = static_cast<String>(p_preset->get(launcher_adaptive_icon_monochrome_option)).strip_edges();
+ if (!path.is_empty()) {
+ print_verbose("Loading adaptive monochrome icon from " + path);
+ ImageLoader::load_image(path, background);
+ }
}
void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
const Ref<Image> &p_main_image,
const Ref<Image> &p_foreground,
- const Ref<Image> &p_background) {
+ const Ref<Image> &p_background,
+ const Ref<Image> &p_monochrome) {
String gradle_build_dir = ExportTemplateManager::get_android_build_directory(p_preset);
// Prepare images to be resized for the icons. If some image ends up being uninitialized,
@@ -1711,6 +1730,14 @@ void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<Editor
launcher_adaptive_icon_backgrounds[i].dimensions, data);
store_file_at_path(gradle_build_dir.path_join(launcher_adaptive_icon_backgrounds[i].export_path), data);
}
+
+ if (p_monochrome.is_valid() && !p_monochrome->is_empty()) {
+ print_verbose("Processing launcher adaptive icon p_monochrome for dimension " + itos(launcher_adaptive_icon_monochromes[i].dimensions) + " into " + launcher_adaptive_icon_monochromes[i].export_path);
+ Vector<uint8_t> data;
+ _process_launcher_icons(launcher_adaptive_icon_monochromes[i].export_path, p_monochrome,
+ launcher_adaptive_icon_monochromes[i].dimensions, data);
+ store_file_at_path(gradle_build_dir.path_join(launcher_adaptive_icon_monochromes[i].export_path), data);
+ }
}
}
@@ -1875,6 +1902,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icon_option, PROPERTY_HINT_FILE, "*.png"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_background_option, PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_monochrome_option, PROPERTY_HINT_FILE, "*.png"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false));
@@ -3035,8 +3063,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
Ref<Image> main_image;
Ref<Image> foreground;
Ref<Image> background;
+ Ref<Image> monochrome;
- load_icon_refs(p_preset, main_image, foreground, background);
+ load_icon_refs(p_preset, main_image, foreground, background, monochrome);
Vector<uint8_t> command_line_flags;
// Write command line flags into the command_line_flags variable.
@@ -3107,7 +3136,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Unable to overwrite res/*.xml files with project name."));
}
// Copies the project icon files into the appropriate Gradle project directory.
- _copy_icons_to_gradle_project(p_preset, main_image, foreground, background);
+ _copy_icons_to_gradle_project(p_preset, main_image, foreground, background, monochrome);
// Write an AndroidManifest.xml file into the Gradle project directory.
_write_tmp_manifest(p_preset, p_give_internet, p_debug);
@@ -3234,8 +3263,11 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
cmdline.push_back(apk_build_command);
}
+ String addons_directory = ProjectSettings::get_singleton()->globalize_path("res://addons");
+
cmdline.push_back("-p"); // argument to specify the start directory.
cmdline.push_back(build_path); // start directory.
+ cmdline.push_back("-Paddons_directory=" + addons_directory); // path to the addon directory as it may contain jar or aar dependencies
cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code.
cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name.
@@ -3446,6 +3478,11 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
_process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
}
}
+ if (monochrome.is_valid() && !monochrome->is_empty()) {
+ if (file == launcher_adaptive_icon_monochromes[i].export_path) {
+ _process_launcher_icons(file, monochrome, launcher_adaptive_icon_monochromes[i].dimensions, data);
+ }
+ }
}
}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 708288fbf4..7e1d626486 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -167,12 +167,13 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
void _process_launcher_icons(const String &p_file_name, const Ref<Image> &p_source_image, int dimension, Vector<uint8_t> &p_data);
- void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background);
+ void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background, Ref<Image> &monochrome);
void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
const Ref<Image> &p_main_image,
const Ref<Image> &p_foreground,
- const Ref<Image> &p_background);
+ const Ref<Image> &p_background,
+ const Ref<Image> &p_monochrome);
static void _create_editor_debug_keystore_if_needed();
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index fdc5753798..308f126d5d 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -63,6 +63,12 @@ dependencies {
implementation files(pluginsBinaries)
}
+ // Automatically pick up local dependencies in res://addons
+ String addonsDirectory = getAddonsDirectory()
+ if (addonsDirectory != null && !addonsDirectory.isBlank()) {
+ implementation fileTree(dir: "$addonsDirectory", include: ['*.jar', '*.aar'])
+ }
+
// .NET dependencies
String jar = '../../../../modules/mono/thirdparty/libSystem.Security.Cryptography.Native.Android.jar'
if (file(jar).exists()) {
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 597a4d5c14..e8921e1bb1 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -408,3 +408,8 @@ ext.shouldUseLegacyPackaging = { ->
// Default behavior for minSdk >= 23
return false
}
+
+ext.getAddonsDirectory = { ->
+ String addonsDirectory = project.hasProperty("addons_directory") ? project.property("addons_directory") : ""
+ return addonsDirectory
+}
diff --git a/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotEditor.kt
index 6cb08ae94b..9dc34f2267 100644
--- a/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotEditor.kt
+++ b/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotEditor.kt
@@ -45,14 +45,14 @@ open class GodotEditor : BaseGodotEditor() {
internal val XR_RUN_GAME_INFO = EditorWindowInfo(GodotXRGame::class.java, 1667, ":GodotXRGame")
- internal const val USE_SCENE_PERMISSION = "com.oculus.permission.USE_SCENE"
+ internal val USE_SCENE_PERMISSIONS = listOf("com.oculus.permission.USE_SCENE", "horizonos.permission.USE_SCENE")
}
override fun getExcludedPermissions(): MutableSet<String> {
val excludedPermissions = super.getExcludedPermissions()
// The USE_SCENE permission is requested when the "xr/openxr/enabled" project setting
// is enabled.
- excludedPermissions.add(USE_SCENE_PERMISSION)
+ excludedPermissions.addAll(USE_SCENE_PERMISSIONS)
return excludedPermissions
}
diff --git a/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotXRGame.kt b/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotXRGame.kt
index 5db2879aad..0c82791e89 100644
--- a/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotXRGame.kt
+++ b/platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotXRGame.kt
@@ -69,7 +69,7 @@ open class GodotXRGame: GodotGame() {
val automaticPermissionsRequestEnabled = automaticallyRequestPermissionsSetting.isNullOrEmpty() ||
automaticallyRequestPermissionsSetting.toBoolean()
if (automaticPermissionsRequestEnabled) {
- permissionsToEnable.add(USE_SCENE_PERMISSION)
+ permissionsToEnable.addAll(USE_SCENE_PERMISSIONS)
}
}
diff --git a/platform/android/java/lib/res/mipmap-anydpi-v26/icon.xml b/platform/android/java/lib/res/mipmap-anydpi-v26/icon.xml
index cfdcca2ab5..bb2ae6bee5 100644
--- a/platform/android/java/lib/res/mipmap-anydpi-v26/icon.xml
+++ b/platform/android/java/lib/res/mipmap-anydpi-v26/icon.xml
@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/icon_background"/>
<foreground android:drawable="@mipmap/icon_foreground"/>
+ <monochrome android:drawable="@mipmap/icon_monochrome"/>
</adaptive-icon>
diff --git a/platform/android/java/lib/res/mipmap/icon_monochrome.png b/platform/android/java/lib/res/mipmap/icon_monochrome.png
new file mode 100644
index 0000000000..28f59ea119
--- /dev/null
+++ b/platform/android/java/lib/res/mipmap/icon_monochrome.png
Binary files differ
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
index 5b1d09e749..567b134234 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -58,6 +58,8 @@ import org.godotengine.godot.input.GodotEditText
import org.godotengine.godot.input.GodotInputHandler
import org.godotengine.godot.io.directory.DirectoryAccessHandler
import org.godotengine.godot.io.file.FileAccessHandler
+import org.godotengine.godot.plugin.AndroidRuntimePlugin
+import org.godotengine.godot.plugin.GodotPlugin
import org.godotengine.godot.plugin.GodotPluginRegistry
import org.godotengine.godot.tts.GodotTTS
import org.godotengine.godot.utils.CommandLineFileParser
@@ -228,7 +230,9 @@ class Godot(private val context: Context) {
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
Log.v(TAG, "Initializing Godot plugin registry")
- GodotPluginRegistry.initializePluginRegistry(this, primaryHost.getHostPlugins(this))
+ val runtimePlugins = mutableSetOf<GodotPlugin>(AndroidRuntimePlugin(this))
+ runtimePlugins.addAll(primaryHost.getHostPlugins(this))
+ GodotPluginRegistry.initializePluginRegistry(this, runtimePlugins)
if (io == null) {
io = GodotIO(activity)
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
index 219631284a..f060c7aaff 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
@@ -216,6 +216,14 @@ public class GodotIO {
return result;
}
+ public boolean hasHardwareKeyboard() {
+ if (edit != null) {
+ return edit.hasHardwareKeyboard();
+ } else {
+ return false;
+ }
+ }
+
public void showKeyboard(String p_existing_text, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
if (edit != null) {
edit.showKeyboard(p_existing_text, GodotEditText.VirtualKeyboardType.values()[p_type], p_max_input_length, p_cursor_start, p_cursor_end);
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 c085bb8886..cacc1643e3 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
@@ -264,7 +264,7 @@ public class GodotEditText extends EditText {
isModifiedKey;
}
- boolean hasHardwareKeyboard() {
+ public boolean hasHardwareKeyboard() {
Configuration config = getResources().getConfiguration();
boolean hasHardwareKeyboardConfig = config.keyboard != Configuration.KEYBOARD_NOKEYS &&
config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/AndroidRuntimePlugin.kt b/platform/android/java/lib/src/org/godotengine/godot/plugin/AndroidRuntimePlugin.kt
new file mode 100644
index 0000000000..edb4e7c357
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/AndroidRuntimePlugin.kt
@@ -0,0 +1,63 @@
+/**************************************************************************/
+/* AndroidRuntimePlugin.kt */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/**************************************************************************/
+
+package org.godotengine.godot.plugin
+
+import org.godotengine.godot.Godot
+
+/**
+ * Provides access to the Android runtime capabilities.
+ *
+ * For example, from gdscript, developers can use [getApplicationContext] to access system services
+ * and check if the device supports vibration.
+ *
+ * var android_runtime = Engine.get_singleton("AndroidRuntime")
+ * if android_runtime:
+ * print("Checking if the device supports vibration")
+ * var vibrator_service = android_runtime.getApplicationContext().getSystemService("vibrator")
+ * if vibrator_service:
+ * if vibrator_service.hasVibrator():
+ * print("Vibration is supported on device!")
+ * else:
+ * printerr("Vibration is not supported on device")
+ * else:
+ * printerr("Unable to retrieve the vibrator service")
+ * else:
+ * printerr("Couldn't find AndroidRuntime singleton")
+ */
+class AndroidRuntimePlugin(godot: Godot) : GodotPlugin(godot) {
+ override fun getPluginName() = "AndroidRuntime"
+
+ @UsedByGodot
+ fun getApplicationContext() = activity?.applicationContext
+
+ @UsedByGodot
+ override fun getActivity() = super.getActivity()
+}
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index c92717e922..6bedbfd157 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -1120,7 +1120,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
return false;
}
-Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
+Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_private_methods_access) {
String class_name_dots = p_class.replace("/", ".");
if (class_cache.has(class_name_dots)) {
return class_cache[class_name_dots];
@@ -1175,7 +1175,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
jint mods = env->CallIntMethod(obj, is_constructor ? Constructor_getModifiers : Method_getModifiers);
- if (!(mods & 0x0001)) {
+ if (!(mods & 0x0001) && (is_constructor || !p_allow_private_methods_access)) {
env->DeleteLocalRef(obj);
continue; //not public bye
}
@@ -1336,7 +1336,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
return java_class;
}
-Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class) {
+Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class, bool p_allow_private_methods_access) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, Ref<JavaClass>());
@@ -1344,12 +1344,12 @@ Ref<JavaClass> JavaClassWrapper::wrap_jclass(jclass p_class) {
String class_name_string = jstring_to_string(class_name, env);
env->DeleteLocalRef(class_name);
- return wrap(class_name_string);
+ return _wrap(class_name_string, p_allow_private_methods_access);
}
JavaClassWrapper *JavaClassWrapper::singleton = nullptr;
-JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
+JavaClassWrapper::JavaClassWrapper() {
singleton = this;
JNIEnv *env = get_jni_env();
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index 49913b9c30..623db39985 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -63,6 +63,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
_get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;IIII)V");
_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
+ _has_hardware_keyboard = p_env->GetMethodID(cls, "hasHardwareKeyboard", "()Z");
_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
_get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I");
_get_system_dir = p_env->GetMethodID(cls, "getSystemDir", "(IZ)Ljava/lang/String;");
@@ -220,6 +221,16 @@ bool GodotIOJavaWrapper::has_vk() {
return (_show_keyboard != nullptr) && (_hide_keyboard != nullptr);
}
+bool GodotIOJavaWrapper::has_hardware_keyboard() {
+ if (_has_hardware_keyboard) {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL_V(env, false);
+ return env->CallBooleanMethod(godot_io_instance, _has_hardware_keyboard);
+ } else {
+ return false;
+ }
+}
+
void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
if (_show_keyboard) {
JNIEnv *env = get_jni_env();
diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h
index c113a13040..0a372641cb 100644
--- a/platform/android/java_godot_io_wrapper.h
+++ b/platform/android/java_godot_io_wrapper.h
@@ -58,6 +58,7 @@ private:
jmethodID _get_unique_id = 0;
jmethodID _show_keyboard = 0;
jmethodID _hide_keyboard = 0;
+ jmethodID _has_hardware_keyboard = 0;
jmethodID _set_screen_orientation = 0;
jmethodID _get_screen_orientation = 0;
jmethodID _get_system_dir = 0;
@@ -80,6 +81,7 @@ public:
Rect2i get_display_safe_area();
String get_unique_id();
bool has_vk();
+ bool has_hardware_keyboard();
void show_vk(const String &p_existing, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end);
void hide_vk();
int get_vk_height();
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 6086f67a1e..1a256959cd 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -32,7 +32,6 @@
#include "android_input_handler.h"
#include "api/java_class_wrapper.h"
-#include "api/jni_singleton.h"
#include "dir_access_jandroid.h"
#include "display_server_android.h"
#include "file_access_android.h"
@@ -209,8 +208,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env
TTS_Android::setup(p_godot_tts);
- java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
- GDREGISTER_CLASS(JNISingleton);
+ java_class_wrapper = memnew(JavaClassWrapper);
return true;
}
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index 75c8dd9528..acb18cc5c5 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -30,6 +30,7 @@
#include "godot_plugin_jni.h"
+#include "api/java_class_wrapper.h"
#include "api/jni_singleton.h"
#include "jni_utils.h"
#include "string_android.h"
@@ -57,11 +58,15 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeR
ERR_FAIL_COND_V(jni_singletons.has(singname), false);
- JNISingleton *s = (JNISingleton *)ClassDB::instantiate("JNISingleton");
- s->set_instance(env->NewGlobalRef(obj));
- jni_singletons[singname] = s;
+ jclass java_class = env->GetObjectClass(obj);
+ Ref<JavaClass> java_class_wrapped = JavaClassWrapper::get_singleton()->wrap_jclass(java_class, true);
+ env->DeleteLocalRef(java_class);
- Engine::get_singleton()->add_singleton(Engine::Singleton(singname, s));
+ Ref<JavaObject> plugin_object = memnew(JavaObject(java_class_wrapped, obj));
+ JNISingleton *plugin_singleton = memnew(JNISingleton(plugin_object));
+ jni_singletons[singname] = plugin_singleton;
+
+ Engine::get_singleton()->add_singleton(Engine::Singleton(singname, plugin_singleton));
return true;
}
@@ -75,7 +80,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
String mname = jstring_to_string(name, env);
String retval = jstring_to_string(ret, env);
Vector<Variant::Type> types;
- String cs = "(";
int stringCount = env->GetArrayLength(args);
@@ -83,18 +87,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
jstring string = (jstring)env->GetObjectArrayElement(args, i);
const String rawString = jstring_to_string(string, env);
types.push_back(get_jni_type(rawString));
- cs += get_jni_sig(rawString);
- }
-
- cs += ")";
- cs += get_jni_sig(retval);
- jclass cls = env->GetObjectClass(s->get_instance());
- jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
- if (!mid) {
- print_line("Failed getting method ID " + mname);
}
- s->add_method(mname, mid, types, get_jni_type(retval));
+ s->add_method(mname, types, get_jni_type(retval));
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types) {
diff --git a/platform/android/rendering_context_driver_vulkan_android.cpp b/platform/android/rendering_context_driver_vulkan_android.cpp
index a306a121f8..51fb1ca18f 100644
--- a/platform/android/rendering_context_driver_vulkan_android.cpp
+++ b/platform/android/rendering_context_driver_vulkan_android.cpp
@@ -32,11 +32,7 @@
#ifdef VULKAN_ENABLED
-#ifdef USE_VOLK
-#include <volk.h>
-#else
-#include <vulkan/vulkan.h>
-#endif
+#include "drivers/vulkan/godot_vulkan.h"
const char *RenderingContextDriverVulkanAndroid::_get_platform_surface_extension() const {
return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
diff --git a/platform/ios/SCsub b/platform/ios/SCsub
index cff7dcc1fd..959a657aac 100644
--- a/platform/ios/SCsub
+++ b/platform/ios/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index 989a7f21f3..20a3a996bc 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -2,7 +2,7 @@ import os
import sys
from typing import TYPE_CHECKING
-from methods import detect_darwin_sdk_path, print_error
+from methods import detect_darwin_sdk_path, print_error, print_warning
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
@@ -156,7 +156,7 @@ def configure(env: "SConsEnvironment"):
env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"])
if env["metal"] and env["arch"] != "arm64":
- # Only supported on arm64, so skip it for x86_64 builds.
+ print_warning("Target architecture '{}' does not support the Metal rendering driver".format(env["arch"]))
env["metal"] = False
if env["metal"]:
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index bbb758074d..7f199db997 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -41,11 +41,7 @@
#if defined(VULKAN_ENABLED)
#import "rendering_context_driver_vulkan_ios.h"
-#ifdef USE_VOLK
-#include <volk.h>
-#else
-#include <vulkan/vulkan.h>
-#endif
+#include "drivers/vulkan/godot_vulkan.h"
#endif // VULKAN_ENABLED
#if defined(METAL_ENABLED)
@@ -228,6 +224,7 @@ public:
void virtual_keyboard_set_height(int height);
virtual int virtual_keyboard_get_height() const override;
+ virtual bool has_hardware_keyboard() const override;
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index e51d43bd89..dcc6ce9218 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -45,6 +45,8 @@
#import <sys/utsname.h>
+#import <GameController/GameController.h>
+
static const float kDisplayServerIOSAcceleration = 1.f;
DisplayServerIOS *DisplayServerIOS::get_singleton() {
@@ -756,6 +758,14 @@ int DisplayServerIOS::virtual_keyboard_get_height() const {
return virtual_keyboard_height;
}
+bool DisplayServerIOS::has_hardware_keyboard() const {
+ if (@available(iOS 14.0, *)) {
+ return [GCKeyboard coalescedKeyboard];
+ } else {
+ return false;
+ }
+}
+
void DisplayServerIOS::clipboard_set(const String &p_text) {
[UIPasteboard generalPasteboard].string = [NSString stringWithUTF8String:p_text.utf8()];
}
diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
index 1d4a944dc4..9e6f191faa 100644
--- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml
+++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
@@ -96,39 +96,156 @@
<member name="icons/app_store_1024x1024" type="String" setter="" getter="">
App Store application icon file. If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
- <member name="icons/ipad_76x76" type="String" setter="" getter="">
- Home screen application icon file on iPad (1x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ <member name="icons/app_store_1024x1024_dark" type="String" setter="" getter="">
+ App Store application icon file, dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/app_store_1024x1024_tinted" type="String" setter="" getter="">
+ App Store application icon file, tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/icon_1024x1024" type="String" setter="" getter="">
+ Base application icon used to generate other icons. If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/icon_1024x1024_dark" type="String" setter="" getter="">
+ Base application icon used to generate other icons, dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/icon_1024x1024_tinted" type="String" setter="" getter="">
+ Base application icon used to generate other icons, tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_128x128" type="String" setter="" getter="">
+ iOS application 64x64 icon file (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_128x128_dark" type="String" setter="" getter="">
+ iOS application 64x64 icon file (2x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_128x128_tinted" type="String" setter="" getter="">
+ iOS application 64x64 icon file (2x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_136x136" type="String" setter="" getter="">
+ iOS application 68x68 icon file (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_136x136_dark" type="String" setter="" getter="">
+ iOS application 68x68 icon file (2x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_136x136_tinted" type="String" setter="" getter="">
+ iOS application 68x68 icon file (2x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_192x192" type="String" setter="" getter="">
+ iOS application 64x64 icon file (3x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_192x192_dark" type="String" setter="" getter="">
+ iOS application 64x64 icon file (3x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ios_192x192_tinted" type="String" setter="" getter="">
+ iOS application 64x64 icon file (3x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/ipad_152x152" type="String" setter="" getter="">
Home screen application icon file on iPad (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/ipad_152x152_dark" type="String" setter="" getter="">
+ Home screen application icon file on iPad (2x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ipad_152x152_tinted" type="String" setter="" getter="">
+ Home screen application icon file on iPad (2x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="icons/ipad_167x167" type="String" setter="" getter="">
Home screen application icon file on iPad (3x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/ipad_167x167_dark" type="String" setter="" getter="">
+ Home screen application icon file on iPad (3x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/ipad_167x167_tinted" type="String" setter="" getter="">
+ Home screen application icon file on iPad (3x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="icons/iphone_120x120" type="String" setter="" getter="">
Home screen application icon file on iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/iphone_120x120_dark" type="String" setter="" getter="">
+ Home screen application icon file on iPhone (2x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/iphone_120x120_tinted" type="String" setter="" getter="">
+ Home screen application icon file on iPhone (2x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="icons/iphone_180x180" type="String" setter="" getter="">
Home screen application icon file on iPhone (3x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/iphone_180x180_dark" type="String" setter="" getter="">
+ Home screen application icon file on iPhone (3x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/iphone_180x180_tinted" type="String" setter="" getter="">
+ Home screen application icon file on iPhone (3x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="icons/notification_40x40" type="String" setter="" getter="">
Notification icon file on iPad and iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/notification_40x40_dark" type="String" setter="" getter="">
+ Notification icon file on iPad and iPhone (2x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/notification_40x40_tinted" type="String" setter="" getter="">
+ Notification icon file on iPad and iPhone (2x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="icons/notification_60x60" type="String" setter="" getter="">
Notification icon file on iPhone (3x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/notification_60x60_dark" type="String" setter="" getter="">
+ Notification icon file on iPhone (3x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/notification_60x60_tinted" type="String" setter="" getter="">
+ Notification icon file on iPhone (3x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/notification_76x76" type="String" setter="" getter="">
+ Notification icon file on iPad and iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/notification_76x76_dark" type="String" setter="" getter="">
+ Notification icon file on iPad and iPhone (2x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/notification_76x76_tinted" type="String" setter="" getter="">
+ Notification icon file on iPad and iPhone (2x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/notification_114x114" type="String" setter="" getter="">
+ Notification icon file on iPad and iPhone (3x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/notification_114x114_dark" type="String" setter="" getter="">
+ Notification icon file on iPad and iPhone (3x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/notification_114x114_tinted" type="String" setter="" getter="">
+ Notification icon file on iPad and iPhone (3x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="icons/settings_58x58" type="String" setter="" getter="">
Application settings icon file on iPad and iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/settings_58x58_dark" type="String" setter="" getter="">
+ Application settings icon file on iPad and iPhone (2x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/settings_58x58_tinted" type="String" setter="" getter="">
+ Application settings icon file on iPad and iPhone (2x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="icons/settings_87x87" type="String" setter="" getter="">
Application settings icon file on iPhone (3x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
- <member name="icons/spotlight_40x40" type="String" setter="" getter="">
- Spotlight icon file on iPad (1x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ <member name="icons/settings_87x87_dark" type="String" setter="" getter="">
+ Application settings icon file on iPhone (3x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/settings_87x87_tinted" type="String" setter="" getter="">
+ Application settings icon file on iPhone (3x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/spotlight_80x80" type="String" setter="" getter="">
Spotlight icon file on iPad and iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/spotlight_80x80_dark" type="String" setter="" getter="">
+ Spotlight icon file on iPad and iPhone (2x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/spotlight_80x80_tinted" type="String" setter="" getter="">
+ Spotlight icon file on iPad and iPhone (2x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/spotlight_120x120" type="String" setter="" getter="">
+ Spotlight icon file on iPad and iPhone (3x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/spotlight_120x120_dark" type="String" setter="" getter="">
+ Spotlight icon file on iPad and iPhone (3x DPI), dark version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
+ <member name="icons/spotlight_120x120_tinted" type="String" setter="" getter="">
+ Spotlight icon file on iPad and iPhone (3x DPI), tinted version. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="privacy/active_keyboard_access_reasons" type="int" setter="" getter="">
The reasons your app use active keyboard API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url].
</member>
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index b99e825540..d6cd2e0f3c 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -79,33 +79,37 @@ struct IconInfo {
};
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 },
+ // Settings on iPhone, iPad Pro, iPad, iPad mini
+ { PNAME("icons/settings_58x58"), "universal", "Icon-58", "58", "2x", "29x29", false },
+ { PNAME("icons/settings_87x87"), "universal", "Icon-87", "87", "3x", "29x29", 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 },
+ // Notifications on iPhone, iPad Pro, iPad, iPad mini
+ { PNAME("icons/notification_40x40"), "universal", "Icon-40", "40", "2x", "20x20", false },
+ { PNAME("icons/notification_60x60"), "universal", "Icon-60", "60", "3x", "20x20", false },
+ { PNAME("icons/notification_76x76"), "universal", "Icon-76", "76", "2x", "38x38", false },
+ { PNAME("icons/notification_114x114"), "universal", "Icon-114", "114", "3x", "38x38", false },
+
+ // Spotlight on iPhone, iPad Pro, iPad, iPad mini
+ { PNAME("icons/spotlight_80x80"), "universal", "Icon-80", "80", "2x", "40x40", false },
+ { PNAME("icons/spotlight_120x120"), "universal", "Icon-120", "120", "3x", "40x40", false },
+
+ // Home Screen on iPhone
+ { PNAME("icons/iphone_120x120"), "universal", "Icon-120-1", "120", "2x", "60x60", false },
+ { PNAME("icons/iphone_180x180"), "universal", "Icon-180", "180", "3x", "60x60", false },
+
+ // Home Screen on iPad Pro
+ { PNAME("icons/ipad_167x167"), "universal", "Icon-167", "167", "2x", "83.5x83.5", false },
+
+ // Home Screen on iPad, iPad mini
+ { PNAME("icons/ipad_152x152"), "universal", "Icon-152", "152", "2x", "76x76", false },
+
+ { PNAME("icons/ios_128x128"), "universal", "Icon-128", "128", "2x", "64x64", false },
+ { PNAME("icons/ios_192x192"), "universal", "Icon-192", "192", "3x", "64x64", false },
+
+ { PNAME("icons/ios_136x136"), "universal", "Icon-136", "136", "2x", "68x68", 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 }
+ { PNAME("icons/app_store_1024x1024"), "universal", "Icon-1024", "1024", "1x", "1024x1024", true },
};
struct APIAccessInfo {
@@ -250,7 +254,7 @@ bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPre
}
bool advanced_options_enabled = p_preset->are_advanced_options_enabled();
- if (p_option.begins_with("privacy") || p_option == "application/generate_simulator_library_if_missing") {
+ if (p_option.begins_with("privacy") || p_option == "application/generate_simulator_library_if_missing" || (p_option.begins_with("icons/") && !p_option.begins_with("icons/icon") && !p_option.begins_with("icons/app_store"))) {
return advanced_options_enabled;
}
@@ -368,11 +372,17 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
}
}
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/icon_1024x1024", PROPERTY_HINT_FILE, "*.svg,*.png,*.webp,*.jpg,*.jpeg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/icon_1024x1024_dark", PROPERTY_HINT_FILE, "*.svg,*.png,*.webp,*.jpg,*.jpeg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/icon_1024x1024_tinted", PROPERTY_HINT_FILE, "*.svg,*.png,*.webp,*.jpg,*.jpeg"), ""));
+
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::STRING, String(icon_infos[i].preset_key), PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, String(icon_infos[i].preset_key) + "_dark", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, String(icon_infos[i].preset_key) + "_tinted", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
}
}
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));
@@ -883,72 +893,127 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
+ enum IconColorMode {
+ ICON_NORMAL,
+ ICON_DARK,
+ ICON_TINTED,
+ ICON_MAX,
+ };
+
+ bool first_icon = true;
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 = 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);
+ for (int color_mode = ICON_NORMAL; color_mode < ICON_MAX; color_mode++) {
+ IconInfo info = icon_infos[i];
+ int side_size = String(info.actual_size_side).to_int();
+ String key = info.preset_key;
+ String exp_name = info.export_name;
+ if (color_mode == ICON_DARK) {
+ key += "_dark";
+ exp_name += "_dark";
+ } else if (color_mode == ICON_TINTED) {
+ key += "_tinted";
+ exp_name += "_tinted";
+ }
+ exp_name += ".png";
+ String icon_path = p_preset->get(key);
+ bool resize_waning = true;
+ if (icon_path.is_empty()) {
+ // Load and resize base icon.
+ key = "icons/icon_1024x1024";
+ if (color_mode == ICON_DARK) {
+ key += "_dark";
+ } else if (color_mode == ICON_TINTED) {
+ key += "_tinted";
+ }
+ icon_path = p_preset->get(key);
+ resize_waning = false;
}
- if (err) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path));
- return err;
+ if (icon_path.is_empty()) {
+ if (color_mode != ICON_NORMAL) {
+ continue;
+ }
+ // Resize main app 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) {
+ 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 + exp_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 + exp_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;
+ }
+ } else {
+ // Load custom icon and resize if required.
+ 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) {
+ if (resize_waning) {
+ 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 + exp_name);
+ } else if (img->get_width() != side_size || img->get_height() != side_size) {
+ if (resize_waning) {
+ 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, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
+ err = img->save_png(p_iconset_dir + exp_name);
+ } else if (!icon_path.ends_with(".png")) {
+ err = img->save_png(p_iconset_dir + exp_name);
+ } else {
+ err = da->copy(icon_path, p_iconset_dir + exp_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;
+ }
}
- } else {
- // Load custom icon and resize if required
- 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 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, (Image::Interpolation)(p_preset->get("application/icon_interpolation").operator int()));
- err = img->save_png(p_iconset_dir + info.export_name);
+ sizes += String(info.actual_size_side) + "\n";
+ if (first_icon) {
+ first_icon = false;
} else {
- err = da->copy(icon_path, p_iconset_dir + info.export_name);
+ json_description += ",";
+ }
+ json_description += String("{");
+ if (color_mode != ICON_NORMAL) {
+ json_description += String("\"appearances\":[{");
+ json_description += String("\"appearance\":\"luminosity\",");
+ if (color_mode == ICON_DARK) {
+ json_description += String("\"value\":\"dark\"");
+ } else if (color_mode == ICON_TINTED) {
+ json_description += String("\"value\":\"tinted\"");
+ }
+ json_description += String("}],");
}
-
- if (err) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path));
- return err;
+ json_description += String("\"idiom\":") + "\"" + info.idiom + "\",";
+ json_description += String("\"platform\":\"ios\",");
+ json_description += String("\"size\":") + "\"" + info.unscaled_size + "\",";
+ if (String(info.scale) != "1x") {
+ json_description += String("\"scale\":") + "\"" + info.scale + "\",";
}
+ json_description += String("\"filename\":") + "\"" + exp_name + "\"";
+ json_description += String("}");
}
- sizes += String(info.actual_size_side) + "\n";
- if (i > 0) {
- json_description += ",";
- }
- json_description += String("{");
- json_description += String("\"idiom\":") + "\"" + info.idiom + "\",";
- json_description += String("\"size\":") + "\"" + info.unscaled_size + "\",";
- json_description += String("\"scale\":") + "\"" + info.scale + "\",";
- json_description += String("\"filename\":") + "\"" + info.export_name + "\"";
- json_description += String("}");
}
- json_description += "]}";
+ json_description += "],\"info\":{\"author\":\"xcode\",\"version\":1}}";
Ref<FileAccess> json_file = FileAccess::open(p_iconset_dir + "Contents.json", FileAccess::WRITE);
if (json_file.is_null()) {
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index 35b87ea647..590238be77 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -56,11 +56,7 @@
#import <QuartzCore/CAMetalLayer.h>
#if defined(VULKAN_ENABLED)
-#ifdef USE_VOLK
-#include <volk.h>
-#else
-#include <vulkan/vulkan.h>
-#endif
+#include "drivers/vulkan/godot_vulkan.h"
#endif // VULKAN_ENABLED
#endif
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
index 0802b528f4..4def765e9c 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index d1de760f34..a67434527c 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -256,10 +256,6 @@ def configure(env: "SConsEnvironment"):
if not env["builtin_enet"]:
env.ParseConfig("pkg-config libenet --cflags --libs")
- if not env["builtin_squish"]:
- # libsquish doesn't reliably install its .pc file, so some distros lack it.
- env.Append(LIBS=["libsquish"])
-
if not env["builtin_zstd"]:
env.ParseConfig("pkg-config libzstd --cflags --libs")
diff --git a/platform/linuxbsd/wayland/SCsub b/platform/linuxbsd/wayland/SCsub
index 89b586845c..1a8e243728 100644
--- a/platform/linuxbsd/wayland/SCsub
+++ b/platform/linuxbsd/wayland/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
diff --git a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp
index 0417ba95eb..8abcc464ba 100644
--- a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp
+++ b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp
@@ -32,11 +32,7 @@
#include "rendering_context_driver_vulkan_wayland.h"
-#ifdef USE_VOLK
-#include <volk.h>
-#else
-#include <vulkan/vulkan.h>
-#endif
+#include "drivers/vulkan/godot_vulkan.h"
const char *RenderingContextDriverVulkanWayland::_get_platform_surface_extension() const {
return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h
index ad2e843a74..819a1205d6 100644
--- a/platform/linuxbsd/wayland/wayland_thread.h
+++ b/platform/linuxbsd/wayland/wayland_thread.h
@@ -665,7 +665,7 @@ private:
.preferred_buffer_transform = _wl_surface_on_preferred_buffer_transform,
};
- static constexpr struct wl_callback_listener frame_wl_callback_listener {
+ static constexpr struct wl_callback_listener frame_wl_callback_listener = {
.done = _frame_wl_callback_on_done,
};
@@ -683,7 +683,7 @@ private:
.name = _wl_seat_on_name,
};
- static constexpr struct wl_callback_listener cursor_frame_callback_listener {
+ static constexpr struct wl_callback_listener cursor_frame_callback_listener = {
.done = _cursor_frame_callback_on_done,
};
diff --git a/platform/linuxbsd/x11/SCsub b/platform/linuxbsd/x11/SCsub
index 75fe584ad5..b76b98447f 100644
--- a/platform/linuxbsd/x11/SCsub
+++ b/platform/linuxbsd/x11/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 7949f80f24..293623e594 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -2055,7 +2055,7 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window
return;
}
- if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN) {
+ if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN || window_get_mode(p_window) == WINDOW_MODE_MAXIMIZED) {
Point2i position = screen_get_position(p_screen);
Size2i size = screen_get_size(p_screen);
@@ -2998,11 +2998,7 @@ bool DisplayServerX11::window_is_focused(WindowID p_window) const {
const WindowData &wd = windows[p_window];
- Window focused_window;
- int focus_ret_state;
- XGetInputFocus(x11_display, &focused_window, &focus_ret_state);
-
- return wd.x11_window == focused_window;
+ return wd.focused;
}
bool DisplayServerX11::window_can_draw(WindowID p_window) const {
@@ -3050,7 +3046,7 @@ void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_win
XWindowAttributes xwa;
XSync(x11_display, False);
XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa);
- if (xwa.map_state == IsViewable) {
+ if (xwa.map_state == IsViewable && _window_focus_check()) {
_set_input_focus(wd.x11_xim_window, RevertToParent);
}
XSetICFocus(wd.xic);
@@ -4319,7 +4315,7 @@ bool DisplayServerX11::_window_focus_check() {
bool has_focus = false;
for (const KeyValue<int, DisplayServerX11::WindowData> &wid : windows) {
- if (wid.value.x11_window == focused_window) {
+ if (wid.value.x11_window == focused_window || (wid.value.xic && wid.value.ime_active && wid.value.x11_xim_window == focused_window)) {
has_focus = true;
break;
}
diff --git a/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp
index 3f505d000c..cbcf07852b 100644
--- a/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp
+++ b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp
@@ -32,11 +32,7 @@
#include "rendering_context_driver_vulkan_x11.h"
-#ifdef USE_VOLK
-#include <volk.h>
-#else
-#include <vulkan/vulkan.h>
-#endif
+#include "drivers/vulkan/godot_vulkan.h"
const char *RenderingContextDriverVulkanX11::_get_platform_surface_extension() const {
return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
diff --git a/platform/macos/SCsub b/platform/macos/SCsub
index a10262c524..3924e79fb6 100644
--- a/platform/macos/SCsub
+++ b/platform/macos/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index e35423d41f..a8968b592e 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -2,12 +2,16 @@ import os
import sys
from typing import TYPE_CHECKING
-from methods import detect_darwin_sdk_path, get_compiler_version, is_vanilla_clang, print_error
+from methods import detect_darwin_sdk_path, get_compiler_version, is_vanilla_clang, print_error, print_warning
from platform_methods import detect_arch, detect_mvk
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
+# To match other platforms
+STACK_SIZE = 8388608
+STACK_SIZE_SANITIZERS = 30 * 1024 * 1024
+
def get_name():
return "macOS"
@@ -183,6 +187,10 @@ def configure(env: "SConsEnvironment"):
env.Append(CCFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-fsanitize=thread"])
+ env.Append(LINKFLAGS=["-Wl,-stack_size," + hex(STACK_SIZE_SANITIZERS)])
+ else:
+ env.Append(LINKFLAGS=["-Wl,-stack_size," + hex(STACK_SIZE)])
+
if env["use_coverage"]:
env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])
@@ -241,7 +249,7 @@ def configure(env: "SConsEnvironment"):
env.Append(LINKFLAGS=["-rpath", "@executable_path/../Frameworks", "-rpath", "@executable_path"])
if env["metal"] and env["arch"] != "arm64":
- # Only supported on arm64, so skip it for x86_64 builds.
+ print_warning("Target architecture '{}' does not support the Metal rendering driver".format(env["arch"]))
env["metal"] = False
extra_frameworks = set()
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index f6c1d11028..48cc7bbba3 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -1893,6 +1893,12 @@ void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_wind
was_fullscreen = true;
}
+ bool was_maximized = false;
+ if (!was_fullscreen && NSEqualRects([wd.window_object frame], [[wd.window_object screen] visibleFrame])) {
+ [wd.window_object zoom:nil];
+ was_maximized = true;
+ }
+
Rect2i srect = screen_get_usable_rect(p_screen);
Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
Size2i wsize = window_get_size(p_window);
@@ -1901,6 +1907,10 @@ void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_wind
wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3);
window_set_position(wpos, p_window);
+ if (was_maximized) {
+ [wd.window_object zoom:nil];
+ }
+
if (was_fullscreen) {
// Re-enter fullscreen mode.
[wd.window_object toggleFullScreen:nil];
diff --git a/platform/macos/godot_menu_delegate.mm b/platform/macos/godot_menu_delegate.mm
index 3f7dfac3de..16fdd0d189 100644
--- a/platform/macos/godot_menu_delegate.mm
+++ b/platform/macos/godot_menu_delegate.mm
@@ -102,7 +102,11 @@
} else {
// Otherwise redirect event to the engine.
if (DisplayServer::get_singleton()) {
- [[[NSApplication sharedApplication] keyWindow] sendEvent:event];
+ if ([[NSApplication sharedApplication] keyWindow].sheet) {
+ [[[[NSApplication sharedApplication] keyWindow] sheetParent] sendEvent:event];
+ } else {
+ [[[NSApplication sharedApplication] keyWindow] sendEvent:event];
+ }
}
}
diff --git a/platform/web/SCsub b/platform/web/SCsub
index e81f2ec516..b30bf20f26 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
from methods import print_error
diff --git a/platform/web/detect.py b/platform/web/detect.py
index bf75c2f9fc..735e2eaf4f 100644
--- a/platform/web/detect.py
+++ b/platform/web/detect.py
@@ -199,6 +199,11 @@ def configure(env: "SConsEnvironment"):
cc_version = get_compiler_version(env)
cc_semver = (cc_version["major"], cc_version["minor"], cc_version["patch"])
+ # Minimum emscripten requirements.
+ if cc_semver < (3, 1, 62):
+ print_error("The minimum emscripten version to build Godot is 3.1.62, detected: %s.%s.%s" % cc_semver)
+ sys.exit(255)
+
env.Prepend(CPPPATH=["#platform/web"])
env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"])
@@ -210,14 +215,12 @@ def configure(env: "SConsEnvironment"):
env.Append(LINKFLAGS=["-sOFFSCREEN_FRAMEBUFFER=1"])
# Disables the use of *glGetProcAddress() which is inefficient.
# See https://emscripten.org/docs/tools_reference/settings_reference.html#gl-enable-get-proc-address
- if cc_semver >= (3, 1, 51):
- env.Append(LINKFLAGS=["-sGL_ENABLE_GET_PROC_ADDRESS=0"])
+ env.Append(LINKFLAGS=["-sGL_ENABLE_GET_PROC_ADDRESS=0"])
if env["javascript_eval"]:
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
- stack_size_opt = "STACK_SIZE" if cc_semver >= (3, 1, 25) else "TOTAL_STACK"
- env.Append(LINKFLAGS=["-s%s=%sKB" % (stack_size_opt, env["stack_size"])])
+ env.Append(LINKFLAGS=["-s%s=%sKB" % ("STACK_SIZE", env["stack_size"])])
if env["threads"]:
# Thread support (via SharedArrayBuffer).
@@ -237,30 +240,21 @@ def configure(env: "SConsEnvironment"):
env["proxy_to_pthread"] = False
if env["lto"] != "none":
- # Workaround https://github.com/emscripten-core/emscripten/issues/19781.
- if cc_semver >= (3, 1, 42) and cc_semver < (3, 1, 46):
- env.Append(LINKFLAGS=["-Wl,-u,scalbnf"])
# Workaround https://github.com/emscripten-core/emscripten/issues/16836.
- if cc_semver >= (3, 1, 47):
- env.Append(LINKFLAGS=["-Wl,-u,_emscripten_run_callback_on_thread"])
+ env.Append(LINKFLAGS=["-Wl,-u,_emscripten_run_callback_on_thread"])
if env["dlink_enabled"]:
if env["proxy_to_pthread"]:
print_warning("GDExtension support requires proxy_to_pthread=no, disabling proxy to pthread.")
env["proxy_to_pthread"] = False
- if cc_semver < (3, 1, 14):
- print_error("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
- sys.exit(255)
-
env.Append(CCFLAGS=["-sSIDE_MODULE=2"])
env.Append(LINKFLAGS=["-sSIDE_MODULE=2"])
env.Append(CCFLAGS=["-fvisibility=hidden"])
env.Append(LINKFLAGS=["-fvisibility=hidden"])
env.extra_suffix = ".dlink" + env.extra_suffix
- # WASM_BIGINT is needed since emscripten ≥ 3.1.41
- needs_wasm_bigint = cc_semver >= (3, 1, 41)
+ env.Append(LINKFLAGS=["-sWASM_BIGINT"])
# Run the main application in a web worker
if env["proxy_to_pthread"]:
@@ -269,11 +263,6 @@ def configure(env: "SConsEnvironment"):
env.Append(LINKFLAGS=["-sEXPORTED_RUNTIME_METHODS=['_emscripten_proxy_main']"])
# https://github.com/emscripten-core/emscripten/issues/18034#issuecomment-1277561925
env.Append(LINKFLAGS=["-sTEXTDECODER=0"])
- # BigInt support to pass object pointers between contexts
- needs_wasm_bigint = True
-
- if needs_wasm_bigint:
- env.Append(LINKFLAGS=["-sWASM_BIGINT"])
# Reduce code size by generating less support code (e.g. skip NodeJS support).
env.Append(LINKFLAGS=["-sENVIRONMENT=web,worker"])
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index 5faab74d7b..efe3c95496 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -214,6 +214,9 @@ Error EditorExportPlatformWeb::_add_manifest_icon(const String &p_path, const St
}
Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
+ List<String> preset_features;
+ get_preset_features(p_preset, &preset_features);
+
String proj_name = GLOBAL_GET("application/config/name");
if (proj_name.is_empty()) {
proj_name = "Godot Game";
@@ -239,7 +242,10 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
cache_files.push_back(name + ".icon.png");
cache_files.push_back(name + ".apple-touch-icon.png");
}
- cache_files.push_back(name + ".worker.js");
+
+ if (preset_features.find("threads")) {
+ cache_files.push_back(name + ".worker.js");
+ }
cache_files.push_back(name + ".audio.worklet.js");
cache_files.push_back(name + ".audio.position.worklet.js");
replaces["___GODOT_CACHE___"] = Variant(cache_files).to_json_string();
diff --git a/platform/web/js/libs/library_godot_audio.js b/platform/web/js/libs/library_godot_audio.js
index 40fb0c356c..aaf986b966 100644
--- a/platform/web/js/libs/library_godot_audio.js
+++ b/platform/web/js/libs/library_godot_audio.js
@@ -868,7 +868,10 @@ class Bus {
* @returns {void}
*/
static move(fromIndex, toIndex) {
- const movedBus = GodotAudio.Bus.getBus(fromIndex);
+ const movedBus = GodotAudio.Bus.getBusOrNull(fromIndex);
+ if (movedBus == null) {
+ return;
+ }
const buses = GodotAudio.buses.filter((_, i) => i !== fromIndex);
// Inserts at index.
buses.splice(toIndex - 1, 0, movedBus);
@@ -1424,7 +1427,10 @@ const _GodotAudio = {
* @returns {void}
*/
remove_sample_bus: function (index) {
- const bus = GodotAudio.Bus.getBus(index);
+ const bus = GodotAudio.Bus.getBusOrNull(index);
+ if (bus == null) {
+ return;
+ }
bus.clear();
},
@@ -1454,8 +1460,17 @@ const _GodotAudio = {
* @returns {void}
*/
set_sample_bus_send: function (busIndex, sendIndex) {
- const bus = GodotAudio.Bus.getBus(busIndex);
- bus.setSend(GodotAudio.Bus.getBus(sendIndex));
+ const bus = GodotAudio.Bus.getBusOrNull(busIndex);
+ if (bus == null) {
+ // Cannot send from an invalid bus.
+ return;
+ }
+ let targetBus = GodotAudio.Bus.getBusOrNull(sendIndex);
+ if (targetBus == null) {
+ // Send to master.
+ targetBus = GodotAudio.Bus.getBus(0);
+ }
+ bus.setSend(targetBus);
},
/**
@@ -1465,7 +1480,10 @@ const _GodotAudio = {
* @returns {void}
*/
set_sample_bus_volume_db: function (busIndex, volumeDb) {
- const bus = GodotAudio.Bus.getBus(busIndex);
+ const bus = GodotAudio.Bus.getBusOrNull(busIndex);
+ if (bus == null) {
+ return;
+ }
bus.setVolumeDb(volumeDb);
},
@@ -1476,7 +1494,10 @@ const _GodotAudio = {
* @returns {void}
*/
set_sample_bus_solo: function (busIndex, enable) {
- const bus = GodotAudio.Bus.getBus(busIndex);
+ const bus = GodotAudio.Bus.getBusOrNull(busIndex);
+ if (bus == null) {
+ return;
+ }
bus.solo(enable);
},
@@ -1487,7 +1508,10 @@ const _GodotAudio = {
* @returns {void}
*/
set_sample_bus_mute: function (busIndex, enable) {
- const bus = GodotAudio.Bus.getBus(busIndex);
+ const bus = GodotAudio.Bus.getBusOrNull(busIndex);
+ if (bus == null) {
+ return;
+ }
bus.mute(enable);
},
},
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index f8ed8b73f5..1d17e7b325 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from misc.utility.scons_hints import *
Import("env")
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index db4c743595..0ee52a09a7 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -390,8 +390,6 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
env.AppendUnique(CPPDEFINES=["R128_STDC_ONLY"])
env.extra_suffix = ".llvm" + env.extra_suffix
- env["MAXLINELENGTH"] = 8192 # Windows Vista and beyond, so always applicable.
-
if env["silence_msvc"] and not env.GetOption("clean"):
from tempfile import mkstemp
@@ -620,18 +618,16 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
sys.exit(255)
- env.Append(CCFLAGS=["-flto=thin"])
- env.Append(LINKFLAGS=["-flto=thin"])
+ env.AppendUnique(CCFLAGS=["-flto=thin"])
elif env["use_llvm"]:
- env.Append(CCFLAGS=["-flto"])
- env.Append(LINKFLAGS=["-flto"])
+ env.AppendUnique(CCFLAGS=["-flto"])
else:
env.AppendUnique(CCFLAGS=["/GL"])
- env.AppendUnique(ARFLAGS=["/LTCG"])
- if env["progress"]:
- env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"])
- else:
- env.AppendUnique(LINKFLAGS=["/LTCG"])
+ if env["progress"]:
+ env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"])
+ else:
+ env.AppendUnique(LINKFLAGS=["/LTCG"])
+ env.AppendUnique(ARFLAGS=["/LTCG"])
if vcvars_msvc_config:
env.Prepend(CPPPATH=[p for p in str(os.getenv("INCLUDE")).split(";")])
@@ -666,7 +662,7 @@ def get_ar_version(env):
print_warning("Couldn't check version of `ar`.")
return ret
- match = re.search(r"GNU ar \(GNU Binutils\) (\d+)\.(\d+)(?:\.(\d+))?", output)
+ match = re.search(r"GNU ar(?: \(GNU Binutils\)| version) (\d+)\.(\d+)(?:\.(\d+))?", output)
if match:
ret["major"] = int(match[1])
ret["minor"] = int(match[2])
@@ -792,8 +788,9 @@ def configure_mingw(env: "SConsEnvironment"):
env["CXX"] = mingw_bin_prefix + "g++"
if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
env["AS"] = mingw_bin_prefix + "as"
- if try_cmd("gcc-ar --version", env["mingw_prefix"], env["arch"]):
- env["AR"] = mingw_bin_prefix + "gcc-ar"
+ ar = "ar" if os.name == "nt" else "gcc-ar"
+ if try_cmd(f"{ar} --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + ar
if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index ed9d5244a3..ffa3840181 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1520,6 +1520,7 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
rendering_device->screen_create(window_id);
}
#endif
+ wd.initialized = true;
return window_id;
}
@@ -1813,6 +1814,13 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi
Size2 size = screen_get_size(p_screen);
MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE);
+ } else if (wd.maximized) {
+ Point2 pos = screen_get_position(p_screen) + _get_screens_origin();
+ Size2 size = screen_get_size(p_screen);
+
+ ShowWindow(wd.hWnd, SW_RESTORE);
+ MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE);
+ ShowWindow(wd.hWnd, SW_MAXIMIZE);
} else {
Rect2i srect = screen_get_usable_rect(p_screen);
Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
@@ -2058,7 +2066,7 @@ Size2i DisplayServerWindows::window_get_size_with_decorations(WindowID p_window)
return Size2();
}
-void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
+void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
// Windows docs for window styles:
// https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
// https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles
@@ -2067,12 +2075,16 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
r_style_ex = WS_EX_WINDOWEDGE;
if (p_main_window) {
r_style_ex |= WS_EX_APPWINDOW;
- r_style |= WS_VISIBLE;
+ if (p_initialized) {
+ r_style |= WS_VISIBLE;
+ }
}
if (p_fullscreen || p_borderless) {
r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
- if (p_maximized) {
+ if (p_minimized) {
+ r_style |= WS_MINIMIZE;
+ } else if (p_maximized) {
r_style |= WS_MAXIMIZE;
}
if (!p_fullscreen) {
@@ -2087,13 +2099,19 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
}
} else {
if (p_resizable) {
- if (p_maximized) {
+ if (p_minimized) {
+ r_style = WS_OVERLAPPEDWINDOW | WS_MINIMIZE;
+ } else if (p_maximized) {
r_style = WS_OVERLAPPEDWINDOW | WS_MAXIMIZE;
} else {
r_style = WS_OVERLAPPEDWINDOW;
}
} else {
- r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
+ if (p_minimized) {
+ r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MINIMIZE;
+ } else {
+ r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
+ }
}
}
@@ -2101,7 +2119,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
r_style_ex |= WS_EX_TOPMOST | WS_EX_NOACTIVATE;
}
- if (!p_borderless && !p_no_activate_focus) {
+ if (!p_borderless && !p_no_activate_focus && p_initialized) {
r_style |= WS_VISIBLE;
}
@@ -2118,7 +2136,7 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain
DWORD style = 0;
DWORD style_ex = 0;
- _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, style, style_ex);
+ _get_window_style(p_window == MAIN_WINDOW_ID, wd.initialized, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.minimized, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, style, style_ex);
SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
@@ -3962,9 +3980,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
- // WARNING: we get called with events before the window is registered in our collection
+ // WARNING: We get called with events before the window is registered in our collection
// specifically, even the call to CreateWindowEx already calls here while still on the stack,
- // so there is no way to store the window handle in our collection before we get here
+ // so there is no way to store the window handle in our collection before we get here.
if (!window_created) {
// don't let code below operate on incompletely initialized window objects or missing window_id
return _handle_early_window_message(hWnd, uMsg, wParam, lParam);
@@ -5529,7 +5547,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DWORD dwExStyle;
DWORD dwStyle;
- _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
+ _get_window_style(window_id_counter == MAIN_WINDOW_ID, false, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MINIMIZED, p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
RECT WindowRect;
@@ -6361,6 +6379,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
}
+ windows[MAIN_WINDOW_ID].initialized = true;
show_window(MAIN_WINDOW_ID);
#if defined(RD_ENABLED)
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 54e1c9681d..7d6a3e96a6 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -524,6 +524,8 @@ class DisplayServerWindows : public DisplayServer {
bool is_popup = false;
Rect2i parent_safe_rect;
+
+ bool initialized = false;
};
JoypadWindows *joypad = nullptr;
@@ -591,7 +593,7 @@ class DisplayServerWindows : public DisplayServer {
HashMap<int64_t, Vector2> pointer_last_pos;
void _send_window_event(const WindowData &wd, WindowEvent p_event);
- void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
+ void _get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
MouseMode mouse_mode;
int restore_mouse_trails = 0;
diff --git a/platform/windows/gl_manager_windows_native.cpp b/platform/windows/gl_manager_windows_native.cpp
index 8590c46d12..af703f4dfa 100644
--- a/platform/windows/gl_manager_windows_native.cpp
+++ b/platform/windows/gl_manager_windows_native.cpp
@@ -452,8 +452,8 @@ Error GLManagerNative_Windows::window_create(DisplayServer::WindowID p_window_id
return FAILED;
}
- // WARNING: p_window_id is an eternally growing integer since popup windows keep coming and going
- // and each of them has a higher id than the previous, so it must be used in a map not a vector
+ // WARNING: `p_window_id` is an eternally growing integer since popup windows keep coming and going
+ // and each of them has a higher id than the previous, so it must be used in a map not a vector.
_windows[p_window_id] = win;
// make current
diff --git a/platform/windows/rendering_context_driver_vulkan_windows.cpp b/platform/windows/rendering_context_driver_vulkan_windows.cpp
index 445388af89..8ca677fe64 100644
--- a/platform/windows/rendering_context_driver_vulkan_windows.cpp
+++ b/platform/windows/rendering_context_driver_vulkan_windows.cpp
@@ -34,11 +34,7 @@
#include "rendering_context_driver_vulkan_windows.h"
-#ifdef USE_VOLK
-#include <volk.h>
-#else
-#include <vulkan/vulkan.h>
-#endif
+#include "drivers/vulkan/godot_vulkan.h"
const char *RenderingContextDriverVulkanWindows::_get_platform_surface_extension() const {
return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;