summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/display_server_android.cpp3
-rw-r--r--platform/android/export/export.cpp278
-rw-r--r--platform/android/export/gradle_export_util.h2
-rw-r--r--platform/android/java/app/build.gradle29
-rw-r--r--platform/android/java/app/config.gradle31
-rw-r--r--platform/android/java/lib/res/values/dimens.xml4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java46
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java80
-rw-r--r--platform/android/logo.pngbin1459 -> 951 bytes
-rw-r--r--platform/iphone/detect.py5
-rw-r--r--platform/iphone/display_server_iphone.mm4
-rw-r--r--platform/iphone/export/export.cpp50
-rw-r--r--platform/iphone/godot_view_renderer.mm33
-rw-r--r--platform/iphone/in_app_store.mm2
-rw-r--r--platform/iphone/ios.mm2
-rw-r--r--platform/iphone/logo.pngbin1489 -> 1297 bytes
-rw-r--r--platform/iphone/os_iphone.h4
-rw-r--r--platform/iphone/os_iphone.mm26
-rw-r--r--platform/iphone/platform_config.h2
-rw-r--r--platform/javascript/engine/engine.js8
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp4
-rw-r--r--platform/linuxbsd/display_server_x11.cpp338
-rw-r--r--platform/linuxbsd/display_server_x11.h5
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp4
-rw-r--r--platform/linuxbsd/os_linuxbsd.h2
-rw-r--r--platform/linuxbsd/platform_config.h2
-rw-r--r--platform/osx/crash_handler_osx.mm4
-rw-r--r--platform/osx/detect.py2
-rw-r--r--platform/osx/display_server_osx.mm19
-rw-r--r--platform/osx/export/export.cpp6
-rw-r--r--platform/osx/logo.pngbin1751 -> 7195 bytes
-rw-r--r--platform/osx/os_osx.h2
-rw-r--r--platform/osx/os_osx.mm4
-rw-r--r--platform/osx/platform_config.h1
-rw-r--r--platform/uwp/export/export.cpp2
-rw-r--r--platform/uwp/os_uwp.cpp9
-rw-r--r--platform/windows/crash_handler_windows.cpp2
-rw-r--r--platform/windows/detect.py21
-rw-r--r--platform/windows/display_server_windows.cpp55
-rw-r--r--platform/windows/os_windows.cpp61
-rw-r--r--platform/windows/platform_config.h2
41 files changed, 697 insertions, 457 deletions
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 235c9ff665..3aa2fb5451 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -36,9 +36,6 @@
#include "java_godot_wrapper.h"
#include "os_android.h"
-#if defined(OPENGL_ENABLED)
-#include "drivers/gles2/rasterizer_gles2.h"
-#endif
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/android/vulkan/vulkan_context_android.h"
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 6f8a968c82..9a144c0a78 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -453,7 +453,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String name;
bool first = true;
for (int i = 0; i < basename.length(); i++) {
- CharType c = basename[i];
+ char32_t c = basename[i];
if (c >= '0' && c <= '9' && first) {
continue;
}
@@ -484,7 +484,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
int segments = 0;
bool first = true;
for (int i = 0; i < pname.length(); i++) {
- CharType c = pname[i];
+ char32_t c = pname[i];
if (first && c == '.') {
if (r_error) {
*r_error = TTR("Package segments must be of non-zero length.");
@@ -723,7 +723,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
return OK;
}
- static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
+ static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
APKExportData *ed = (APKExportData *)p_userdata;
String dst_path = p_path.replace_first("res://", "assets/");
@@ -731,7 +731,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
return OK;
}
- static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
+ static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
return OK;
}
@@ -873,7 +873,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
if (string_flags & UTF8_FLAG) {
} else {
uint32_t len = decode_uint16(&p_manifest[string_at]);
- Vector<CharType> ucstring;
+ Vector<char32_t> ucstring;
ucstring.resize(len + 1);
for (uint32_t j = 0; j < len; j++) {
uint16_t c = decode_uint16(&p_manifest[string_at + 2 + 2 * j]);
@@ -1334,7 +1334,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
} else {
String str;
for (uint32_t i = 0; i < len; i++) {
- CharType c = decode_uint16(&p_bytes[offset + i * 2]);
+ char32_t c = decode_uint16(&p_bytes[offset + i * 2]);
if (c == 0) {
break;
}
@@ -1525,7 +1525,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
public:
- typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total);
+ typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override {
@@ -1554,6 +1554,7 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "custom_template/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), 0));
Vector<PluginConfig> plugins_configs = get_plugins();
for (int i = 0; i < plugins_configs.size(); i++) {
@@ -1974,6 +1975,13 @@ public:
}
}
+ if (int(p_preset->get("custom_template/export_format")) == 1 && /*AAB*/
+ !bool(p_preset->get("custom_template/use_custom_build"))) {
+ valid = false;
+ err += TTR("\"Export AAB\" is only valid when \"Use Custom Build\" is enabled.");
+ err += "\n";
+ }
+
r_error = err;
return valid;
}
@@ -1981,6 +1989,7 @@ public:
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
List<String> list;
list.push_back("apk");
+ list.push_back("aab");
return list;
}
@@ -2007,7 +2016,21 @@ public:
return have_plugins_changed || first_build;
}
- Error get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags) {
+ String get_apk_expansion_fullpath(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ int version_code = p_preset->get("version/code");
+ String package_name = p_preset->get("package/unique_name");
+ String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
+ String fullpath = p_path.get_base_dir().plus_file(apk_file_name);
+ return fullpath;
+ }
+
+ Error save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
+ Error err = save_pack(p_preset, fullpath);
+ return err;
+ }
+
+ void get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags) {
String cmdline = p_preset->get("command_line/extra_args");
Vector<String> command_line_strings = cmdline.strip_edges().split(" ");
for (int i = 0; i < command_line_strings.size(); i++) {
@@ -2021,17 +2044,8 @@ public:
bool apk_expansion = p_preset->get("apk_expansion/enable");
if (apk_expansion) {
- int version_code = p_preset->get("version/code");
- String package_name = p_preset->get("package/unique_name");
- String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
- String fullpath = p_path.get_base_dir().plus_file(apk_file_name);
+ String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
String apk_expansion_public_key = p_preset->get("apk_expansion/public_key");
- Error err = save_pack(p_preset, fullpath);
-
- if (err != OK) {
- EditorNode::add_io_error("Could not write expansion package file: " + apk_file_name);
- return err;
- }
command_line_strings.push_back("--use_apk_expansion");
command_line_strings.push_back("--apk_expansion_md5");
@@ -2077,7 +2091,6 @@ public:
copymem(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
}
}
- return OK;
}
Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, String apk_path, EditorProgress ep) {
@@ -2171,11 +2184,16 @@ public:
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
String src_apk;
+ Error err;
EditorProgress ep("export", "Exporting for Android", 105, true);
bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build"));
+ int export_format = int(p_preset->get("custom_template/export_format"));
bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG);
+ bool _signed = p_preset->get("package/signed");
+ bool apk_expansion = p_preset->get("apk_expansion/enable");
+ Vector<String> enabled_abis = get_enabled_abis(p_preset);
Ref<Image> main_image;
Ref<Image> foreground;
@@ -2183,25 +2201,48 @@ public:
load_icon_refs(p_preset, main_image, foreground, background);
+ Vector<uint8_t> command_line_flags;
+ // Write command line flags into the command_line_flags variable.
+ get_command_line_flags(p_preset, p_path, p_flags, command_line_flags);
+
+ if (export_format == 1) {
+ if (!p_path.ends_with(".aab")) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid filename! Android App Bundle requires the *.aab extension."));
+ return ERR_UNCONFIGURED;
+ }
+ if (apk_expansion) {
+ EditorNode::get_singleton()->show_warning(TTR("APK Expansion not compatible with Android App Bundle."));
+ return ERR_UNCONFIGURED;
+ }
+ }
+ if (export_format == 0 && !p_path.ends_with(".apk")) {
+ EditorNode::get_singleton()->show_warning(
+ TTR("Invalid filename! Android APK requires the *.apk extension."));
+ return ERR_UNCONFIGURED;
+ }
+ if (export_format > 1 || export_format < 0) {
+ EditorNode::add_io_error("Unsupported export format!\n");
+ return ERR_UNCONFIGURED; //TODO: is this the right error?
+ }
+
if (use_custom_build) {
- //re-generate build.gradle and AndroidManifest.xml
- { //test that installed build version is alright
- FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
- return ERR_UNCONFIGURED;
- }
- String version = f->get_line().strip_edges();
- if (version != VERSION_FULL_CONFIG) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
- return ERR_UNCONFIGURED;
- }
+ //test that installed build version is alright
+ FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
+ return ERR_UNCONFIGURED;
+ }
+ String version = f->get_line().strip_edges();
+ if (version != VERSION_FULL_CONFIG) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
+ return ERR_UNCONFIGURED;
}
+ String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path");
+ ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/custom_build_sdk_path'.");
// TODO: should we use "package/name" or "application/config/name"?
String project_name = get_project_name(p_preset->get("package/name"));
- // instead of calling _fix_resources
- Error err = _create_project_name_strings_files(p_preset, project_name);
+ err = _create_project_name_strings_files(p_preset, project_name); //project name localization.
if (err != OK) {
EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name");
}
@@ -2209,14 +2250,32 @@ public:
_copy_icons_to_gradle_project(p_preset, main_image, foreground, background);
// Write an AndroidManifest.xml file into the Gradle project directory.
_write_tmp_manifest(p_preset, p_give_internet, p_debug);
- //build project if custom build is enabled
- String sdk_path = EDITOR_GET("export/android/custom_build_sdk_path");
- ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/custom_build_sdk_path'.");
+ //stores all the project files inside the Gradle project directory. Also includes all ABIs
+ if (!apk_expansion) {
+ DirAccess *da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da_res->dir_exists("res://android/build/assets")) {
+ DirAccess *da_assets = DirAccess::open("res://android/build/assets");
+ da_assets->erase_contents_recursive();
+ da_res->remove("res://android/build/assets");
+ }
+ err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, NULL, ignore_so_file);
+ if (err != OK) {
+ EditorNode::add_io_error("Could not export project files to gradle project\n");
+ return err;
+ }
+ } else {
+ err = save_apk_expansion_file(p_preset, p_path);
+ if (err != OK) {
+ EditorNode::add_io_error("Could not write expansion package file!");
+ return err;
+ }
+ }
+ store_file_at_path("res://android/build/assets/_cl_", command_line_flags);
OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
-
String build_command;
+
#ifdef WINDOWS_ENABLED
build_command = "gradlew.bat";
#else
@@ -2224,12 +2283,12 @@ public:
#endif
String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
-
build_command = build_path.plus_file(build_command);
String package_name = get_package_name(p_preset->get("package/unique_name"));
String version_code = itos(p_preset->get("version/code"));
String version_name = p_preset->get("version/name");
+ String enabled_abi_string = String("|").join(enabled_abis);
Vector<PluginConfig> enabled_plugins = get_enabled_plugins(p_preset);
String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins);
@@ -2241,10 +2300,20 @@ public:
if (clean_build_required) {
cmdline.push_back("clean");
}
- cmdline.push_back("build");
+
+ String build_type = p_debug ? "Debug" : "Release";
+ if (export_format == 1) {
+ String bundle_build_command = vformat("bundle%s", build_type);
+ cmdline.push_back(bundle_build_command);
+ } else if (export_format == 0) {
+ String apk_build_command = vformat("assemble%s", build_type);
+ cmdline.push_back(apk_build_command);
+ }
+
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.
+ cmdline.push_back("-Pexport_enabled_abis=" + enabled_abi_string); // argument to specify enabled ABIs.
cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies.
cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies.
cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies.
@@ -2262,35 +2331,54 @@ public:
EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation."));
return ERR_CANT_CREATE;
}
- if (p_debug) {
- src_apk = build_path.plus_file("build/outputs/apk/debug/android_debug.apk");
- } else {
- src_apk = build_path.plus_file("build/outputs/apk/release/android_release.apk");
+
+ List<String> copy_args;
+ String copy_command;
+ if (export_format == 1) {
+ copy_command = vformat("copyAndRename%sAab", build_type);
+ } else if (export_format == 0) {
+ copy_command = vformat("copyAndRename%sApk", build_type);
}
- if (!FileAccess::exists(src_apk)) {
- EditorNode::get_singleton()->show_warning(TTR("No build apk generated at: ") + "\n" + src_apk);
+ copy_args.push_back(copy_command);
+
+ copy_args.push_back("-p"); // argument to specify the start directory.
+ copy_args.push_back(build_path); // start directory.
+
+ String export_filename = p_path.get_file();
+ String export_path = p_path.get_base_dir();
+
+ copy_args.push_back("-Pexport_path=file:" + export_path);
+ copy_args.push_back("-Pexport_filename=" + export_filename);
+
+ int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
+ if (copy_result != 0) {
+ EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs."));
return ERR_CANT_CREATE;
}
-
- } else {
+ if (_signed) {
+ err = sign_apk(p_preset, p_debug, p_path, ep);
+ if (err != OK) {
+ return err;
+ }
+ }
+ return OK;
+ }
+ // This is the start of the Legacy build system
+ if (p_debug)
+ src_apk = p_preset->get("custom_template/debug");
+ else
+ src_apk = p_preset->get("custom_template/release");
+ src_apk = src_apk.strip_edges();
+ if (src_apk == "") {
if (p_debug) {
- src_apk = p_preset->get("custom_template/debug");
+ src_apk = find_export_template("android_debug.apk");
} else {
- src_apk = p_preset->get("custom_template/release");
+ src_apk = find_export_template("android_release.apk");
}
-
- src_apk = src_apk.strip_edges();
if (src_apk == "") {
- if (p_debug) {
- src_apk = find_export_template("android_debug.apk");
- } else {
- src_apk = find_export_template("android_release.apk");
- }
- if (src_apk == "") {
- EditorNode::add_io_error("Package not found: " + src_apk);
- return ERR_FILE_NOT_FOUND;
- }
+ EditorNode::add_io_error("Package not found: " + src_apk);
+ return ERR_FILE_NOT_FOUND;
}
}
@@ -2327,19 +2415,13 @@ public:
zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
- bool _signed = p_preset->get("package/signed");
String cmdline = p_preset->get("command_line/extra_args");
String version_name = p_preset->get("version/name");
String package_name = p_preset->get("package/unique_name");
- bool apk_expansion = p_preset->get("apk_expansion/enable");
String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
- Vector<String> enabled_abis = get_enabled_abis(p_preset);
-
- // Prepare images to be resized for the icons. If some image ends up being uninitialized, the default image from the export template will be used.
-
Vector<String> invalid_abis(enabled_abis);
while (ret == UNZ_OK) {
//get filename
@@ -2360,30 +2442,26 @@ public:
unzCloseCurrentFile(pkg);
//write
-
- if (!use_custom_build) {
- if (file == "AndroidManifest.xml") {
- _fix_manifest(p_preset, data, p_give_internet);
- }
- if (file == "resources.arsc") {
- _fix_resources(p_preset, data);
- }
-
- for (int i = 0; i < icon_densities_count; ++i) {
- if (main_image.is_valid() && !main_image->empty()) {
- if (file == launcher_icons[i].export_path) {
- _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
- }
+ if (file == "AndroidManifest.xml") {
+ _fix_manifest(p_preset, data, p_give_internet);
+ }
+ if (file == "resources.arsc") {
+ _fix_resources(p_preset, data);
+ }
+ for (int i = 0; i < icon_densities_count; ++i) {
+ if (main_image.is_valid() && !main_image->empty()) {
+ if (file == launcher_icons[i].export_path) {
+ _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
}
- if (foreground.is_valid() && !foreground->empty()) {
- if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
- _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
- }
+ }
+ if (foreground.is_valid() && !foreground->empty()) {
+ if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
+ _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
}
- if (background.is_valid() && !background->empty()) {
- if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
- _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
- }
+ }
+ if (background.is_valid() && !background->empty()) {
+ if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
+ _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
}
}
}
@@ -2442,18 +2520,26 @@ public:
if (ep.step("Adding files...", 1)) {
CLEANUP_AND_RETURN(ERR_SKIP);
}
- Error err = OK;
+ err = OK;
if (p_flags & DEBUG_FLAG_DUMB_CLIENT) {
APKExportData ed;
ed.ep = &ep;
ed.apk = unaligned_apk;
err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so);
- } else if (!apk_expansion) {
- APKExportData ed;
- ed.ep = &ep;
- ed.apk = unaligned_apk;
- err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
+ } else {
+ if (apk_expansion) {
+ err = save_apk_expansion_file(p_preset, p_path);
+ if (err != OK) {
+ EditorNode::add_io_error("Could not write expansion package file!");
+ return err;
+ }
+ } else {
+ APKExportData ed;
+ ed.ep = &ep;
+ ed.apk = unaligned_apk;
+ err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
+ }
}
if (err != OK) {
@@ -2462,10 +2548,6 @@ public:
CLEANUP_AND_RETURN(ERR_SKIP);
}
- Vector<uint8_t> command_line_flags;
- // Write command line flags into the command_line_flags variable.
- err = get_command_line_flags(p_preset, p_path, p_flags, command_line_flags);
-
zip_fileinfo zipfi = get_zip_fileinfo();
zipOpenNewFileInZip(unaligned_apk,
"assets/_cl_",
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 209a664f8f..95f870bc35 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -99,7 +99,7 @@ Error store_string_at_path(const String &p_path, const String &p_data) {
// It is used by the export_project_files method to save all the asset files into the gradle project.
// It's functionality mirrors that of the method save_apk_file.
// This method will be called ONLY when custom build is enabled.
-Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
+Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
String dst_path = p_path.replace_first("res://", "res://android/build/assets/");
Error err = store_file_at_path(dst_path, p_data);
return err;
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index 3f8d138e8f..ceacfec9e1 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -80,6 +80,11 @@ android {
ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
}
+ ndk {
+ String[] export_abi_list = getExportEnabledABIs()
+ abiFilters export_abi_list
+ }
+
// Feel free to modify the application id to your own.
applicationId getExportPackageName()
versionCode getExportVersionCode()
@@ -125,3 +130,27 @@ android {
}
}
}
+
+task copyAndRenameDebugApk(type: Copy) {
+ from "$buildDir/outputs/apk/debug/android_debug.apk"
+ into getExportPath()
+ rename "android_debug.apk", getExportFilename()
+}
+
+task copyAndRenameReleaseApk(type: Copy) {
+ from "$buildDir/outputs/apk/release/android_release.apk"
+ into getExportPath()
+ rename "android_release.apk", getExportFilename()
+}
+
+task copyAndRenameDebugAab(type: Copy) {
+ from "$buildDir/outputs/bundle/debug/build-debug.aab"
+ into getExportPath()
+ rename "build-debug.aab", getExportFilename()
+}
+
+task copyAndRenameReleaseAab(type: Copy) {
+ from "$buildDir/outputs/bundle/release/build-release.aab"
+ into getExportPath()
+ rename "build-release.aab", getExportFilename()
+}
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 7d5d238100..d1176e6196 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -46,6 +46,37 @@ ext.getExportVersionName = { ->
final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|"
+// get the list of ABIs the project should be exported to
+ext.getExportEnabledABIs = { ->
+ String enabledABIs = project.hasProperty("export_enabled_abis") ? project.property("export_enabled_abis") : "";
+ if (enabledABIs == null || enabledABIs.isEmpty()) {
+ enabledABIs = "armeabi-v7a|arm64-v8a|x86|x86_64|"
+ }
+ Set<String> exportAbiFilter = [];
+ for (String abi_name : enabledABIs.split(PLUGIN_VALUE_SEPARATOR_REGEX)) {
+ if (!abi_name.trim().isEmpty()){
+ exportAbiFilter.add(abi_name);
+ }
+ }
+ return exportAbiFilter;
+}
+
+ext.getExportPath = {
+ String exportPath = project.hasProperty("export_path") ? project.property("export_path") : ""
+ if (exportPath == null || exportPath.isEmpty()) {
+ exportPath = "."
+ }
+ return exportPath
+}
+
+ext.getExportFilename = {
+ String exportFilename = project.hasProperty("export_filename") ? project.property("export_filename") : ""
+ if (exportFilename == null || exportFilename.isEmpty()) {
+ exportFilename = "godot_android"
+ }
+ return exportFilename
+}
+
/**
* Parse the project properties for the 'plugins_maven_repos' property and return the list
* of maven repos.
diff --git a/platform/android/java/lib/res/values/dimens.xml b/platform/android/java/lib/res/values/dimens.xml
new file mode 100644
index 0000000000..9034dbbcc1
--- /dev/null
+++ b/platform/android/java/lib/res/values/dimens.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="text_edit_height">48dp</dimen>
+</resources>
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 35852f31ef..524f32bf5e 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -56,6 +56,8 @@ import android.content.SharedPreferences.Editor;
import android.content.pm.ConfigurationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -75,6 +77,7 @@ import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
@@ -148,8 +151,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
private void setButtonPausedState(boolean paused) {
mStatePaused = paused;
- int stringResourceID = paused ? R.string.text_button_resume :
- R.string.text_button_pause;
+ int stringResourceID = paused ? R.string.text_button_resume : R.string.text_button_pause;
mPauseButton.setText(stringResourceID);
}
@@ -160,8 +162,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
public GodotRenderView mRenderView;
private boolean godot_initialized = false;
- private GodotEditText mEditText;
-
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private Sensor mGravity;
@@ -218,6 +218,13 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
containerLayout = new FrameLayout(activity);
containerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ // GodotEditText layout
+ GodotEditText editText = new GodotEditText(activity);
+ editText.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,
+ (int)getResources().getDimension(R.dimen.text_edit_height)));
+ // ...add to FrameLayout
+ containerLayout.addView(editText);
+
GodotLib.setup(command_line);
final String videoDriver = GodotLib.getGlobal("rendering/quality/driver/driver_name");
@@ -230,9 +237,21 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
View view = mRenderView.getView();
containerLayout.addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ editText.setView(mRenderView);
+ io.setEdit(editText);
- mEditText = new GodotEditText(activity, mRenderView);
- io.setEdit(mEditText);
+ view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ Point fullSize = new Point();
+ activity.getWindowManager().getDefaultDisplay().getSize(fullSize);
+ Rect gameSize = new Rect();
+ mRenderView.getView().getWindowVisibleDisplayFrame(gameSize);
+
+ final int keyboardHeight = fullSize.y - gameSize.bottom;
+ GodotLib.setVirtualKeyboardHeight(keyboardHeight);
+ }
+ });
mRenderView.queueOnRenderThread(new Runnable() {
@Override
@@ -448,7 +467,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
final Activity activity = getActivity();
Window window = activity.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
mClipboard = (ClipboardManager)activity.getSystemService(Context.CLIPBOARD_SERVICE);
pluginRegistry = GodotPluginRegistry.initializePluginRegistry(this);
@@ -585,21 +603,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
@Override
- public void onStart() {
- super.onStart();
-
- mRenderView.getView().post(new Runnable() {
- @Override
- public void run() {
- mEditText.onInitView();
- }
- });
- }
-
- @Override
public void onDestroy() {
- mEditText.onDestroyView();
-
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onMainDestroy();
}
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 6855f91f1c..c95339c583 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
@@ -32,27 +32,16 @@ package org.godotengine.godot.input;
import org.godotengine.godot.*;
-import android.app.Activity;
import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.text.InputFilter;
import android.text.InputType;
import android.util.AttributeSet;
-import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.ViewTreeObserver;
-import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
-import android.widget.FrameLayout;
-import android.widget.PopupWindow;
import java.lang.ref.WeakReference;
@@ -67,8 +56,6 @@ public class GodotEditText extends EditText {
// Fields
// ===========================================================
private GodotRenderView mRenderView;
- private View mKeyboardView;
- private PopupWindow mKeyboardWindow;
private GodotTextInputWrapper mInputWrapper;
private EditHandler sHandler = new EditHandler(this);
private String mOriginText;
@@ -93,52 +80,24 @@ public class GodotEditText extends EditText {
// ===========================================================
// Constructors
// ===========================================================
- public GodotEditText(final Context context, final GodotRenderView view) {
+ public GodotEditText(final Context context) {
super(context);
+ initView();
+ }
- setPadding(0, 0, 0, 0);
- setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
- setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-
- mRenderView = view;
- mInputWrapper = new GodotTextInputWrapper(mRenderView, this);
- setOnEditorActionListener(mInputWrapper);
- view.getView().requestFocus();
-
- // Create a popup window with an invisible layout for the virtual keyboard,
- // so the view can be resized to get the vk height without resizing the main godot view.
- final FrameLayout keyboardLayout = new FrameLayout(context);
- keyboardLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- keyboardLayout.setVisibility(View.INVISIBLE);
- keyboardLayout.addView(this);
- mKeyboardView = keyboardLayout;
-
- mKeyboardWindow = new PopupWindow(keyboardLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- mKeyboardWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- mKeyboardWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
- mKeyboardWindow.setFocusable(true); // for the text edit to work
- mKeyboardWindow.setTouchable(false); // inputs need to go through
-
- keyboardLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- Point fullSize = new Point();
- ((Activity)mRenderView.getView().getContext()).getWindowManager().getDefaultDisplay().getSize(fullSize);
- Rect gameSize = new Rect();
- mKeyboardWindow.getContentView().getWindowVisibleDisplayFrame(gameSize);
-
- final int keyboardHeight = fullSize.y - gameSize.bottom;
- GodotLib.setVirtualKeyboardHeight(keyboardHeight);
- }
- });
+ public GodotEditText(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ initView();
}
- public void onInitView() {
- mKeyboardWindow.showAtLocation(mRenderView.getView(), Gravity.NO_GRAVITY, 0, 0);
+ public GodotEditText(final Context context, final AttributeSet attrs, final int defStyle) {
+ super(context, attrs, defStyle);
+ initView();
}
- public void onDestroyView() {
- mKeyboardWindow.dismiss();
+ protected void initView() {
+ setPadding(0, 0, 0, 0);
+ setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
}
public boolean isMultiline() {
@@ -170,7 +129,7 @@ public class GodotEditText extends EditText {
edit.mInputWrapper.setOriginText(text);
edit.addTextChangedListener(edit.mInputWrapper);
- final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(edit, 0);
}
} break;
@@ -179,7 +138,7 @@ public class GodotEditText extends EditText {
GodotEditText edit = (GodotEditText)msg.obj;
edit.removeTextChangedListener(mInputWrapper);
- final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(edit.getWindowToken(), 0);
edit.mRenderView.getView().requestFocus();
} break;
@@ -193,6 +152,17 @@ public class GodotEditText extends EditText {
}
// ===========================================================
+ // Getter & Setter
+ // ===========================================================
+ public void setView(final GodotRenderView view) {
+ mRenderView = view;
+ if (mInputWrapper == null)
+ mInputWrapper = new GodotTextInputWrapper(mRenderView, this);
+ setOnEditorActionListener(mInputWrapper);
+ view.getView().requestFocus();
+ }
+
+ // ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
diff --git a/platform/android/logo.png b/platform/android/logo.png
index df445f6a9c..f44d360a25 100644
--- a/platform/android/logo.png
+++ b/platform/android/logo.png
Binary files differ
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index f4ef40a0ba..66579c1ad7 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -235,7 +235,10 @@ def configure(env):
env.Append(CPPDEFINES=["ICLOUD_ENABLED"])
env.Prepend(
- CPPPATH=["$IPHONESDK/usr/include", "$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers",]
+ CPPPATH=[
+ "$IPHONESDK/usr/include",
+ "$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers",
+ ]
)
env["ENV"]["CODESIGN_ALLOCATE"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate"
diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm
index 1721da3db6..eea87cecc9 100644
--- a/platform/iphone/display_server_iphone.mm
+++ b/platform/iphone/display_server_iphone.mm
@@ -701,7 +701,7 @@ Error DisplayServerIPhone::native_video_play(String p_path, float p_volume, Stri
if (p_path.begins_with("res://")) {
if (PackedData::get_singleton()->has_path(p_path)) {
- printf("Unable to play %S using the native player as it resides in a .pck file\n", p_path.c_str());
+ printf("Unable to play %s using the native player as it resides in a .pck file\n", p_path.utf8().get_data());
return ERR_INVALID_PARAMETER;
} else {
p_path = p_path.replace("res:/", ProjectSettings::get_singleton()->get_resource_path());
@@ -712,7 +712,7 @@ Error DisplayServerIPhone::native_video_play(String p_path, float p_volume, Stri
memdelete(f);
- printf("Playing video: %S\n", p_path.c_str());
+ printf("Playing video: %s\n", p_path.utf8().get_data());
String file_path = ProjectSettings::get_singleton()->globalize_path(p_path);
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 4a751488cb..97f954ebb2 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -86,6 +86,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
struct IOSExportAsset {
String exported_path;
bool is_framework; // framework is anything linked to the binary, otherwise it's a resource
+ bool should_embed;
};
String _get_additional_plist_content();
@@ -100,7 +101,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset);
void _add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets);
- Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, Vector<IOSExportAsset> &r_exported_assets);
+ Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
@@ -114,7 +115,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
}
for (int i = 0; i < pname.length(); i++) {
- CharType c = pname[i];
+ char32_t c = pname[i];
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
if (r_error) {
*r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
@@ -912,15 +913,6 @@ struct ExportLibsData {
};
void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) {
- Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
- Vector<String> frameworks;
- for (int i = 0; i < export_plugins.size(); ++i) {
- Vector<String> plugin_frameworks = export_plugins[i]->get_ios_frameworks();
- for (int j = 0; j < plugin_frameworks.size(); ++j) {
- frameworks.push_back(plugin_frameworks[j]);
- }
- }
-
// that is just a random number, we just need Godot IDs not to clash with
// existing IDs in the project.
PbxId current_id = { 0x58938401, 0, 0 };
@@ -945,15 +937,19 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
String type;
if (asset.exported_path.ends_with(".framework")) {
- additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
- framework_id = (++current_id).str();
- pbx_embeded_frameworks += framework_id + ",\n";
+ if (asset.should_embed) {
+ additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
+ framework_id = (++current_id).str();
+ pbx_embeded_frameworks += framework_id + ",\n";
+ }
type = "wrapper.framework";
} else if (asset.exported_path.ends_with(".xcframework")) {
- additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
- framework_id = (++current_id).str();
- pbx_embeded_frameworks += framework_id + ",\n";
+ if (asset.should_embed) {
+ additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
+ framework_id = (++current_id).str();
+ pbx_embeded_frameworks += framework_id + ",\n";
+ }
type = "wrapper.xcframework";
} else if (asset.exported_path.ends_with(".dylib")) {
@@ -1026,7 +1022,7 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
}
}
-Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, Vector<IOSExportAsset> &r_exported_assets) {
+Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String binary_name = p_out_dir.get_file().get_basename();
@@ -1035,7 +1031,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
String asset = p_assets[f_idx];
if (!asset.begins_with("res://")) {
// either SDK-builtin or already a part of the export template
- IOSExportAsset exported_asset = { asset, p_is_framework };
+ IOSExportAsset exported_asset = { asset, p_is_framework, p_should_embed };
r_exported_assets.push_back(exported_asset);
} else {
DirAccess *da = DirAccess::create_for_path(asset);
@@ -1101,7 +1097,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
memdelete(filesystem_da);
return err;
}
- IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework };
+ IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed };
r_exported_assets.push_back(exported_asset);
if (create_framework) {
@@ -1165,19 +1161,23 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) {
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
for (int i = 0; i < export_plugins.size(); i++) {
- Vector<String> frameworks = export_plugins[i]->get_ios_frameworks();
- Error err = _export_additional_assets(p_out_dir, frameworks, true, r_exported_assets);
+ Vector<String> linked_frameworks = export_plugins[i]->get_ios_frameworks();
+ Error err = _export_additional_assets(p_out_dir, linked_frameworks, true, false, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
+ Vector<String> embedded_frameworks = export_plugins[i]->get_ios_embedded_frameworks();
+ err = _export_additional_assets(p_out_dir, embedded_frameworks, true, true, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
for (int j = 0; j < project_static_libs.size(); j++) {
project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project
}
- err = _export_additional_assets(p_out_dir, project_static_libs, true, r_exported_assets);
+ err = _export_additional_assets(p_out_dir, project_static_libs, true, true, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files();
- err = _export_additional_assets(p_out_dir, ios_bundle_files, false, r_exported_assets);
+ err = _export_additional_assets(p_out_dir, ios_bundle_files, false, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
}
@@ -1185,7 +1185,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
for (int i = 0; i < p_libraries.size(); ++i) {
library_paths.push_back(p_libraries[i].path);
}
- Error err = _export_additional_assets(p_out_dir, library_paths, true, r_exported_assets);
+ Error err = _export_additional_assets(p_out_dir, library_paths, true, true, r_exported_assets);
ERR_FAIL_COND_V(err, err);
return OK;
diff --git a/platform/iphone/godot_view_renderer.mm b/platform/iphone/godot_view_renderer.mm
index 1fc822b457..045fb451f0 100644
--- a/platform/iphone/godot_view_renderer.mm
+++ b/platform/iphone/godot_view_renderer.mm
@@ -44,7 +44,6 @@
@interface GodotViewRenderer ()
-@property(assign, nonatomic) BOOL hasFinishedLocaleSetup;
@property(assign, nonatomic) BOOL hasFinishedProjectDataSetup;
@property(assign, nonatomic) BOOL hasStartedMain;
@property(assign, nonatomic) BOOL hasFinishedSetup;
@@ -58,9 +57,8 @@
return NO;
}
- if (!self.hasFinishedLocaleSetup) {
- [self setupLocaleAndUUID];
- return YES;
+ if (!OS::get_singleton()) {
+ exit(0);
}
if (!self.hasFinishedProjectDataSetup) {
@@ -79,33 +77,6 @@
return NO;
}
-- (void)setupLocaleAndUUID {
- self.hasFinishedLocaleSetup = YES;
-
- if (!OS::get_singleton()) {
- exit(0);
- }
-
- NSString *locale_code = [[NSLocale currentLocale] localeIdentifier];
- OSIPhone::get_singleton()->set_locale(String::utf8([locale_code UTF8String]));
-
- NSString *uuid;
- if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) {
- uuid = [UIDevice currentDevice].identifierForVendor.UUIDString;
- } else {
- // before iOS 6, so just generate an identifier and store it
- uuid = [[NSUserDefaults standardUserDefaults] objectForKey:@"identiferForVendor"];
- if (!uuid) {
- CFUUIDRef cfuuid = CFUUIDCreate(NULL);
- uuid = [(NSString *)CFUUIDCreateString(NULL, cfuuid) autorelease];
- CFRelease(cfuuid);
- [[NSUserDefaults standardUserDefaults] setObject:uuid forKey:@"identifierForVendor"];
- }
- }
-
- OSIPhone::get_singleton()->set_unique_id(String::utf8([uuid UTF8String]));
-}
-
- (void)setupProjectData {
self.hasFinishedProjectDataSetup = YES;
diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm
index dfec5d7634..1477f92200 100644
--- a/platform/iphone/in_app_store.mm
+++ b/platform/iphone/in_app_store.mm
@@ -138,7 +138,7 @@ Error InAppStore::request_product_info(Dictionary p_params) {
NSMutableArray *array = [[[NSMutableArray alloc] initWithCapacity:pids.size()] autorelease];
for (int i = 0; i < pids.size(); i++) {
- printf("******** adding %ls to product list\n", pids[i].c_str());
+ printf("******** adding %s to product list\n", pids[i].utf8().get_data());
NSString *pid = [[[NSString alloc] initWithUTF8String:pids[i].utf8().get_data()] autorelease];
[array addObject:pid];
};
diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm
index ad26d0ada3..6d7699c0c9 100644
--- a/platform/iphone/ios.mm
+++ b/platform/iphone/ios.mm
@@ -86,7 +86,7 @@ String iOS::get_rate_url(int p_app_id) const {
// ios7 for everything?
ret = templ_iOS7.replace("APP_ID", String::num(p_app_id));
- printf("returning rate url %ls\n", ret.c_str());
+ printf("returning rate url %s\n", ret.utf8().get_data());
return ret;
};
diff --git a/platform/iphone/logo.png b/platform/iphone/logo.png
index 405b6f93ca..966d8aa70a 100644
--- a/platform/iphone/logo.png
+++ b/platform/iphone/logo.png
Binary files differ
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index f3bde46717..c6f95869ee 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -84,8 +84,6 @@ private:
virtual void finalize() override;
String user_data_dir;
- String unique_id;
- String locale_code;
bool is_focused = false;
@@ -118,10 +116,8 @@ public:
void set_user_data_dir(String p_dir);
virtual String get_user_data_dir() const override;
- void set_locale(String p_locale);
virtual String get_locale() const override;
- void set_unique_id(String p_id);
virtual String get_unique_id() const override;
virtual void vibrate_handheld(int p_duration_ms = 500) override;
diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm
index f0bbbd39ca..946fd51923 100644
--- a/platform/iphone/os_iphone.mm
+++ b/platform/iphone/os_iphone.mm
@@ -46,10 +46,6 @@
#import <UIKit/UIKit.h>
#import <dlfcn.h>
-#if defined(OPENGL_ENABLED)
-#include "drivers/gles2/rasterizer_gles2.h"
-#endif
-
#if defined(VULKAN_ENABLED)
#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
#import <QuartzCore/CAMetalLayer.h>
@@ -282,7 +278,7 @@ Error OSIPhone::shell_open(String p_uri) {
return ERR_CANT_OPEN;
}
- printf("opening url %ls\n", p_uri.c_str());
+ printf("opening url %s\n", p_uri.utf8().get_data());
// if (@available(iOS 10, *)) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
@@ -297,7 +293,7 @@ void OSIPhone::set_user_data_dir(String p_dir) {
DirAccess *da = DirAccess::open(p_dir);
user_data_dir = da->get_current_dir();
- printf("setting data dir to %ls from %ls\n", user_data_dir.c_str(), p_dir.c_str());
+ printf("setting data dir to %s from %s\n", user_data_dir.utf8().get_data(), p_dir.utf8().get_data());
memdelete(da);
}
@@ -305,20 +301,20 @@ String OSIPhone::get_user_data_dir() const {
return user_data_dir;
}
-void OSIPhone::set_locale(String p_locale) {
- locale_code = p_locale;
-}
-
String OSIPhone::get_locale() const {
- return locale_code;
-}
+ NSString *preferedLanguage = [NSLocale preferredLanguages].firstObject;
+
+ if (preferedLanguage) {
+ return String::utf8([preferedLanguage UTF8String]).replace("-", "_");
+ }
-void OSIPhone::set_unique_id(String p_id) {
- unique_id = p_id;
+ NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier];
+ return String::utf8([localeIdentifier UTF8String]).replace("-", "_");
}
String OSIPhone::get_unique_id() const {
- return unique_id;
+ NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString;
+ return String::utf8([uuid UTF8String]);
}
void OSIPhone::vibrate_handheld(int p_duration_ms) {
diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h
index bc190ba956..2bbbe47c0d 100644
--- a/platform/iphone/platform_config.h
+++ b/platform/iphone/platform_config.h
@@ -30,8 +30,6 @@
#include <alloca.h>
-#define GLES2_INCLUDE_H <ES2/gl.h>
-
#define PLATFORM_REFCOUNT
#define PTHREAD_RENAME_SELF
diff --git a/platform/javascript/engine/engine.js b/platform/javascript/engine/engine.js
index d709422abb..2630812814 100644
--- a/platform/javascript/engine/engine.js
+++ b/platform/javascript/engine/engine.js
@@ -121,7 +121,7 @@ Function('return this')()['Engine'] = (function() {
if (me.onExit)
me.onExit(code);
me.rtenv = null;
- }
+ };
return new Promise(function(resolve, reject) {
preloader.preloadedFiles.forEach(function(file) {
me.rtenv['copyToFS'](file.path, file.buffer);
@@ -207,18 +207,18 @@ Function('return this')()['Engine'] = (function() {
if (this.rtenv)
this.rtenv.onExecute = onExecute;
this.onExecute = onExecute;
- }
+ };
Engine.prototype.setOnExit = function(onExit) {
this.onExit = onExit;
- }
+ };
Engine.prototype.copyToFS = function(path, buffer) {
if (this.rtenv == null) {
throw new Error("Engine must be inited before copying files");
}
this.rtenv['copyToFS'](path, buffer);
- }
+ };
// Closure compiler exported engine methods.
/** @export */
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
index b3553e961a..e2b88b7704 100644
--- a/platform/linuxbsd/crash_handler_linuxbsd.cpp
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -67,7 +67,7 @@ static void handle_crash(int sig) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
}
- fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
for (size_t i = 1; i < size; i++) {
@@ -109,7 +109,7 @@ static void handle_crash(int sig) {
output.erase(output.length() - 1, 1);
}
- fprintf(stderr, "[%ld] %s (%ls)\n", (long int)i, fname, output.c_str());
+ fprintf(stderr, "[%ld] %s (%s)\n", (long int)i, fname, output.utf8().get_data());
}
free(strings);
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index d35941bdcd..fe9e253cc9 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -39,10 +39,6 @@
#include "main/main.h"
#include "scene/resources/texture.h"
-#if defined(OPENGL_ENABLED)
-#include "drivers/gles2/rasterizer_gles2.h"
-#endif
-
#if defined(VULKAN_ENABLED)
#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
#endif
@@ -87,6 +83,13 @@
#define VALUATOR_TILTX 3
#define VALUATOR_TILTY 4
+//#define DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
+#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
+#define DEBUG_LOG_X11(...) printf(__VA_ARGS__)
+#else
+#define DEBUG_LOG_X11(...)
+#endif
+
static const double abs_resolution_mult = 10000.0;
static const double abs_resolution_range_mult = 10.0;
@@ -701,6 +704,8 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
WindowData &wd = windows[p_id];
+ DEBUG_LOG_X11("delete_sub_window: %lu (%u) \n", wd.x11_window, p_id);
+
while (wd.transient_children.size()) {
window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID);
}
@@ -737,15 +742,31 @@ ObjectID DisplayServerX11::window_get_attached_instance_id(WindowID p_window) co
}
DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const Point2i &p_position) const {
-#warning This is an incorrect implementation, if windows overlap, it should return the topmost visible one or none if occluded by a foreign window
-
+ WindowID found_window = INVALID_WINDOW_ID;
+ WindowID parent_window = INVALID_WINDOW_ID;
+ unsigned int focus_order = 0;
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- Rect2i win_rect = Rect2i(window_get_position(E->key()), window_get_size(E->key()));
+ const WindowData &wd = E->get();
+
+ // Discard windows with no focus.
+ if (wd.focus_order == 0) {
+ continue;
+ }
+
+ // Find topmost window which contains the given position.
+ WindowID window_id = E->key();
+ Rect2i win_rect = Rect2i(window_get_position(window_id), window_get_size(window_id));
if (win_rect.has_point(p_position)) {
- return E->key();
+ // For siblings, pick the window which was focused last.
+ if ((parent_window != wd.transient_parent) || (wd.focus_order > focus_order)) {
+ found_window = window_id;
+ parent_window = wd.transient_parent;
+ focus_order = wd.focus_order;
+ }
}
}
- return INVALID_WINDOW_ID;
+
+ return found_window;
}
void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window) {
@@ -854,24 +875,34 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd_window = windows[p_window];
- ERR_FAIL_COND(wd_window.transient_parent == p_parent);
+ WindowID prev_parent = wd_window.transient_parent;
+ ERR_FAIL_COND(prev_parent == p_parent);
ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient.");
if (p_parent == INVALID_WINDOW_ID) {
//remove transient
- ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
- ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
+ ERR_FAIL_COND(prev_parent == INVALID_WINDOW_ID);
+ ERR_FAIL_COND(!windows.has(prev_parent));
- WindowData &wd_parent = windows[wd_window.transient_parent];
+ WindowData &wd_parent = windows[prev_parent];
wd_window.transient_parent = INVALID_WINDOW_ID;
wd_parent.transient_children.erase(p_window);
XSetTransientForHint(x11_display, wd_window.x11_window, None);
+
+ // Set focus to parent sub window to avoid losing all focus with nested menus.
+ // RevertToPointerRoot is used to make sure we don't lose all focus in case
+ // a subwindow and its parent are both destroyed.
+ if (wd_window.menu_type && !wd_window.no_focus) {
+ if (!wd_parent.no_focus) {
+ XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
+ }
+ }
} else {
ERR_FAIL_COND(!windows.has(p_parent));
- ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
+ ERR_FAIL_COND_MSG(prev_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
WindowData &wd_parent = windows[p_parent];
wd_window.transient_parent = p_parent;
@@ -2297,6 +2328,11 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev
void DisplayServerX11::process_events() {
_THREAD_SAFE_METHOD_
+#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
+ static int frame = 0;
+ ++frame;
+#endif
+
if (app_focused) {
//verify that one of the windows has focus, else send focus out notification
bool focus_found = false;
@@ -2313,6 +2349,7 @@ void DisplayServerX11::process_events() {
if (delta > 250) {
//X11 can go between windows and have no focus for a while, when creating them or something else. Use this as safety to avoid unnecessary focus in/outs.
if (OS::get_singleton()->get_main_loop()) {
+ DEBUG_LOG_X11("All focus lost, triggering NOTIFICATION_APPLICATION_FOCUS_OUT\n");
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
}
app_focused = false;
@@ -2335,6 +2372,10 @@ void DisplayServerX11::process_events() {
XEvent event;
XNextEvent(x11_display, &event);
+ if (XFilterEvent(&event, None)) {
+ continue;
+ }
+
WindowID window_id = MAIN_WINDOW_ID;
// Assign the event to the relevant window
@@ -2345,10 +2386,6 @@ void DisplayServerX11::process_events() {
}
}
- if (XFilterEvent(&event, None)) {
- continue;
- }
-
if (XGetEventData(x11_display, &event.xcookie)) {
if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
@@ -2511,32 +2548,67 @@ void DisplayServerX11::process_events() {
XFreeEventData(x11_display, &event.xcookie);
switch (event.type) {
- case Expose:
+ case MapNotify: {
+ DEBUG_LOG_X11("[%u] MapNotify window=%lu (%u) \n", frame, event.xmap.window, window_id);
+
+ const WindowData &wd = windows[window_id];
+
+ // Set focus when menu window is started.
+ // RevertToPointerRoot is used to make sure we don't lose all focus in case
+ // a subwindow and its parent are both destroyed.
+ if (wd.menu_type && !wd.no_focus) {
+ XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
+ }
+ } break;
+
+ case Expose: {
+ DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count);
+
Main::force_redraw();
- break;
+ } break;
+
+ case NoExpose: {
+ DEBUG_LOG_X11("[%u] NoExpose drawable=%lu (%u) \n", frame, event.xnoexpose.drawable, window_id);
- case NoExpose:
windows[window_id].minimized = true;
- break;
+ } break;
case VisibilityNotify: {
+ DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
+
XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
windows[window_id].minimized = (visibility->state == VisibilityFullyObscured);
} break;
+
case LeaveNotify: {
+ DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
+
if (!mouse_mode_grab) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
}
} break;
+
case EnterNotify: {
+ DEBUG_LOG_X11("[%u] EnterNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
+
if (!mouse_mode_grab) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
}
} break;
- case FocusIn:
- windows[window_id].focused = true;
- _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN);
+
+ case FocusIn: {
+ DEBUG_LOG_X11("[%u] FocusIn window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
+
+ WindowData &wd = windows[window_id];
+
+ wd.focused = true;
+
+ // Keep track of focus order for overlapping windows.
+ static unsigned int focus_order = 0;
+ wd.focus_order = ++focus_order;
+
+ _send_window_event(wd, WINDOW_EVENT_FOCUS_IN);
if (mouse_mode_grab) {
// Show and update the cursor if confined and the window regained focus.
@@ -2560,8 +2632,8 @@ void DisplayServerX11::process_events() {
XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
}*/
#endif
- if (windows[window_id].xic) {
- XSetICFocus(windows[window_id].xic);
+ if (wd.xic) {
+ XSetICFocus(wd.xic);
}
if (!app_focused) {
@@ -2570,12 +2642,17 @@ void DisplayServerX11::process_events() {
}
app_focused = true;
}
- break;
+ } break;
+
+ case FocusOut: {
+ DEBUG_LOG_X11("[%u] FocusOut window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
+
+ WindowData &wd = windows[window_id];
+
+ wd.focused = false;
- case FocusOut:
- windows[window_id].focused = false;
Input::get_singleton()->release_pressed_events();
- _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT);
+ _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT);
if (mouse_mode_grab) {
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
@@ -2604,14 +2681,26 @@ void DisplayServerX11::process_events() {
}
xi.state.clear();
#endif
- if (windows[window_id].xic) {
- XSetICFocus(windows[window_id].xic);
+ if (wd.xic) {
+ XSetICFocus(wd.xic);
+ }
+ } break;
+
+ case ConfigureNotify: {
+ DEBUG_LOG_X11("[%u] ConfigureNotify window=%lu (%u), event=%lu, above=%lu, override_redirect=%u \n", frame, event.xconfigure.window, window_id, event.xconfigure.event, event.xconfigure.above, event.xconfigure.override_redirect);
+
+ const WindowData &wd = windows[window_id];
+
+ // Set focus when menu window is re-used.
+ // RevertToPointerRoot is used to make sure we don't lose all focus in case
+ // a subwindow and its parent are both destroyed.
+ if (wd.menu_type && !wd.no_focus) {
+ XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
- break;
- case ConfigureNotify:
_window_changed(&event);
- break;
+ } break;
+
case ButtonPress:
case ButtonRelease: {
/* exit in case of a mouse button press */
@@ -2638,7 +2727,18 @@ void DisplayServerX11::process_events() {
mb->set_pressed((event.type == ButtonPress));
+ const WindowData &wd = windows[window_id];
+
if (event.type == ButtonPress) {
+ DEBUG_LOG_X11("[%u] ButtonPress window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
+
+ // Ensure window focus on click.
+ // RevertToPointerRoot is used to make sure we don't lose all focus in case
+ // a subwindow and its parent are both destroyed.
+ if (!wd.no_focus) {
+ XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
+ }
+
uint64_t diff = OS::get_singleton()->get_ticks_usec() / 1000 - last_click_ms;
if (mb->get_button_index() == last_click_button_index) {
@@ -2657,6 +2757,33 @@ void DisplayServerX11::process_events() {
last_click_ms += diff;
last_click_pos = Point2i(event.xbutton.x, event.xbutton.y);
}
+ } else {
+ DEBUG_LOG_X11("[%u] ButtonRelease window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
+
+ if (!wd.focused) {
+ // Propagate the event to the focused window,
+ // because it's received only on the topmost window.
+ // Note: This is needed for drag & drop to work between windows,
+ // because the engine expects events to keep being processed
+ // on the same window dragging started.
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ const WindowData &wd_other = E->get();
+ WindowID window_id_other = E->key();
+ if (wd_other.focused) {
+ if (window_id_other != window_id) {
+ int x, y;
+ Window child;
+ XTranslateCoordinates(x11_display, wd.x11_window, wd_other.x11_window, event.xbutton.x, event.xbutton.y, &x, &y, &child);
+
+ mb->set_window_id(window_id_other);
+ mb->set_position(Vector2(x, y));
+ mb->set_global_position(mb->get_position());
+ Input::get_singleton()->accumulate_input_event(mb);
+ }
+ break;
+ }
+ }
+ }
}
Input::get_singleton()->accumulate_input_event(mb);
@@ -2706,6 +2833,9 @@ void DisplayServerX11::process_events() {
break;
}
+ const WindowData &wd = windows[window_id];
+ bool focused = wd.focused;
+
if (mouse_mode == MOUSE_MODE_CAPTURED) {
if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) {
break;
@@ -2714,7 +2844,7 @@ void DisplayServerX11::process_events() {
Point2i new_center = pos;
pos = last_mouse_pos + xi.relative_motion;
center = new_center;
- do_mouse_warp = windows[window_id].focused; // warp the cursor if we're focused in
+ do_mouse_warp = focused; // warp the cursor if we're focused in
}
if (!last_mouse_pos_valid) {
@@ -2756,14 +2886,11 @@ void DisplayServerX11::process_events() {
}
mm->set_tilt(xi.tilt);
- // Make the absolute position integral so it doesn't look _too_ weird :)
- Point2i posi(pos);
-
_get_key_modifier_state(event.xmotion.state, mm);
mm->set_button_mask(mouse_get_button_state());
- mm->set_position(posi);
- mm->set_global_position(posi);
- Input::get_singleton()->set_mouse_position(posi);
+ mm->set_position(pos);
+ mm->set_global_position(pos);
+ Input::get_singleton()->set_mouse_position(pos);
mm->set_speed(Input::get_singleton()->get_last_mouse_speed());
mm->set_relative(rel);
@@ -2774,8 +2901,32 @@ void DisplayServerX11::process_events() {
// Don't propagate the motion event unless we have focus
// this is so that the relative motion doesn't get messed up
// after we regain focus.
- if (windows[window_id].focused || !mouse_mode_grab) {
+ if (focused) {
Input::get_singleton()->accumulate_input_event(mm);
+ } else {
+ // Propagate the event to the focused window,
+ // because it's received only on the topmost window.
+ // Note: This is needed for drag & drop to work between windows,
+ // because the engine expects events to keep being processed
+ // on the same window dragging started.
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ const WindowData &wd_other = E->get();
+ if (wd_other.focused) {
+ int x, y;
+ Window child;
+ XTranslateCoordinates(x11_display, wd.x11_window, wd_other.x11_window, event.xmotion.x, event.xmotion.y, &x, &y, &child);
+
+ Point2i pos_focused(x, y);
+
+ mm->set_window_id(E->key());
+ mm->set_position(pos_focused);
+ mm->set_global_position(pos_focused);
+ mm->set_speed(Input::get_singleton()->get_last_mouse_speed());
+ Input::get_singleton()->accumulate_input_event(mm);
+
+ break;
+ }
+ }
}
} break;
@@ -3152,11 +3303,38 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
- WindowID id;
+ WindowID id = window_id_counter++;
+ WindowData &wd = windows[id];
+
+ if ((id != MAIN_WINDOW_ID) && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) {
+ wd.menu_type = true;
+ }
+
+ if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
+ wd.menu_type = true;
+ wd.no_focus = true;
+ }
+
+ // Setup for menu subwindows:
+ // - override_redirect forces the WM not to interfere with the window, to avoid delays due to
+ // handling decorations and placement.
+ // On the other hand, focus changes need to be handled manually when this is set.
+ // - save_under is a hint for the WM to keep the content of windows behind to avoid repaint.
+ if (wd.menu_type) {
+ windowAttributes.override_redirect = True;
+ windowAttributes.save_under = True;
+ valuemask |= CWOverrideRedirect | CWSaveUnder;
+ }
+
{
- WindowData wd;
wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
+ // Enable receiving notification when the window is initialized (MapNotify)
+ // so the focus can be set at the right time.
+ if (wd.menu_type && !wd.no_focus) {
+ XSelectInput(x11_display, wd.x11_window, StructureNotifyMask);
+ }
+
//associate PID
// make PID known to X11
{
@@ -3231,58 +3409,26 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
_update_context(wd);
- id = window_id_counter++;
-
- windows[id] = wd;
-
- {
- bool make_utility = false;
-
- if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
- Hints hints;
- Atom property;
- hints.flags = 2;
- hints.decorations = 0;
- property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
- XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
-
- make_utility = true;
- }
- if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
- make_utility = true;
- }
-
- if (make_utility) {
- //this one seems to disable the fade animations for regular windows
- //but has the drawback that will not get focus by default, so
- //we need to force it, unless no focus requested
-
- Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
- Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
-
- XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
-
- if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) {
- //but as utility appears unfocused, it needs to be forcefuly focused, unless no focus requested
- XEvent xev;
- Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
+ if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = 0;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+ }
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = net_active_window;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = 1;
- xev.xclient.data.l[1] = CurrentTime;
+ if (wd.menu_type) {
+ // Set Utility type to disable fade animations.
+ Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
+ Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
- }
- } else {
- Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
- Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
+ XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
+ } else {
+ Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
+ Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
- XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
- }
+ XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
}
_update_size_hints(id);
@@ -3303,8 +3449,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
XFree(visualInfo);
}
- WindowData &wd = windows[id];
-
window_set_mode(p_mode, id);
//sync size
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 8e1f941bbf..57cee910a0 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -132,6 +132,9 @@ class DisplayServerX11 : public DisplayServer {
ObjectID instance_id;
+ bool menu_type = false;
+ bool no_focus = false;
+
//better to guess on the fly, given WM can change it
//WindowMode mode;
bool fullscreen = false; //OS can't exit from this mode
@@ -141,6 +144,8 @@ class DisplayServerX11 : public DisplayServer {
Vector2i last_position_before_fs;
bool focused = false;
bool minimized = false;
+
+ unsigned int focus_order = 0;
};
Map<WindowID, WindowData> windows;
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 8c6f3b1167..e00a32e3ba 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -88,7 +88,9 @@ void OS_LinuxBSD::finalize() {
#endif
#ifdef JOYDEV_ENABLED
- memdelete(joypad);
+ if (joypad) {
+ memdelete(joypad);
+ }
#endif
}
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index 4295721c68..cd4fbd9db5 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -48,7 +48,7 @@ class OS_LinuxBSD : public OS_Unix {
bool force_quit;
#ifdef JOYDEV_ENABLED
- JoypadLinux *joypad;
+ JoypadLinux *joypad = nullptr;
#endif
#ifdef ALSA_ENABLED
diff --git a/platform/linuxbsd/platform_config.h b/platform/linuxbsd/platform_config.h
index ac30519132..764666681f 100644
--- a/platform/linuxbsd/platform_config.h
+++ b/platform/linuxbsd/platform_config.h
@@ -35,5 +35,3 @@
#include <stdlib.h>
#define PTHREAD_BSD_SET_NAME
#endif
-
-#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h"
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
index 5da0118686..9fb2f63935 100644
--- a/platform/osx/crash_handler_osx.mm
+++ b/platform/osx/crash_handler_osx.mm
@@ -90,7 +90,7 @@ static void handle_crash(int sig) {
if (OS::get_singleton()->get_main_loop())
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
- fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
void *load_addr = (void *)load_address();
@@ -142,7 +142,7 @@ static void handle_crash(int sig) {
}
}
- fprintf(stderr, "[%zu] %ls\n", i, output.c_str());
+ fprintf(stderr, "[%zu] %s\n", i, output.utf8().get_data());
}
free(strings);
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 272ae1b620..6fc1dc65af 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -1,6 +1,5 @@
import os
import sys
-import subprocess
from methods import detect_darwin_sdk_path
@@ -76,6 +75,7 @@ def configure(env):
elif env["target"] == "debug":
env.Prepend(CCFLAGS=["-g3"])
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
+ env.Prepend(LINKFLAGS=["-Xlinker", "-no_deduplicate"])
## Architecture
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 4c04151791..adfb47324e 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -45,7 +45,6 @@
#include <IOKit/hid/IOHIDLib.h>
#if defined(OPENGL_ENABLED)
-#include "drivers/gles2/rasterizer_gles2.h"
//TODO - reimplement OpenGLES
#import <AppKit/NSOpenGLView.h>
@@ -312,8 +311,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
DS_OSX->window_set_transient(wd.transient_children.front()->get(), DisplayServerOSX::INVALID_WINDOW_ID);
}
- DS_OSX->windows.erase(window_id);
-
if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) {
DisplayServerOSX::WindowData &pwd = DS_OSX->windows[wd.transient_parent];
[pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to parent.
@@ -333,6 +330,8 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
DS_OSX->context_vulkan->window_destroy(window_id);
}
#endif
+
+ DS_OSX->windows.erase(window_id);
}
- (void)windowDidEnterFullScreen:(NSNotification *)notification {
@@ -2375,7 +2374,11 @@ void DisplayServerOSX::_update_window(WindowData p_wd) {
[p_wd.window_object setHidesOnDeactivate:YES];
} else {
// Reset these when our window is not a borderless window that covers up the screen
- [p_wd.window_object setLevel:NSNormalWindowLevel];
+ if (p_wd.on_top) {
+ [p_wd.window_object setLevel:NSFloatingWindowLevel];
+ } else {
+ [p_wd.window_object setLevel:NSNormalWindowLevel];
+ }
[p_wd.window_object setHidesOnDeactivate:NO];
}
}
@@ -3805,9 +3808,11 @@ DisplayServerOSX::~DisplayServerOSX() {
}
//destroy all windows
- for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- [E->get().window_object setContentView:nil];
- [E->get().window_object close];
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E;) {
+ Map<WindowID, WindowData>::Element *F = E;
+ E = E->next();
+ [F->get().window_object setContentView:nil];
+ [F->get().window_object close];
}
//destroy drivers
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index ae45e0734d..9f2160dd9e 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -78,7 +78,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
}
for (int i = 0; i < pname.length(); i++) {
- CharType c = pname[i];
+ char32_t c = pname[i];
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
if (r_error) {
*r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
@@ -95,8 +95,8 @@ protected:
virtual void get_export_options(List<ExportOption> *r_options) override;
public:
- virtual String get_name() const override { return "Mac OSX"; }
- virtual String get_os_name() const override { return "OSX"; }
+ virtual String get_name() const override { return "macOS"; }
+ virtual String get_os_name() const override { return "macOS"; }
virtual Ref<Texture2D> get_logo() const override { return logo; }
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
diff --git a/platform/osx/logo.png b/platform/osx/logo.png
index 834bbf3ba6..b5a660b165 100644
--- a/platform/osx/logo.png
+++ b/platform/osx/logo.png
Binary files differ
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 9204a145bf..5a9e43450f 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -44,7 +44,7 @@ class OS_OSX : public OS_Unix {
bool force_quit;
- JoypadOSX *joypad_osx;
+ JoypadOSX *joypad_osx = nullptr;
#ifdef COREAUDIO_ENABLED
AudioDriverCoreAudio audio_driver;
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index c4eb5407af..399a29cbe0 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -145,7 +145,9 @@ void OS_OSX::finalize() {
delete_main_loop();
- memdelete(joypad_osx);
+ if (joypad_osx) {
+ memdelete(joypad_osx);
+ }
}
void OS_OSX::set_main_loop(MainLoop *p_main_loop) {
diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h
index 155f37ed55..e657aca955 100644
--- a/platform/osx/platform_config.h
+++ b/platform/osx/platform_config.h
@@ -30,5 +30,4 @@
#include <alloca.h>
-#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h"
#define PTHREAD_RENAME_SELF
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index ede0d7c76b..5679ec3eac 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -961,7 +961,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
return true;
}
- static Error save_appx_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
+ static Error save_appx_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
AppxPackager *packager = (AppxPackager *)p_userdata;
String dst_path = p_path.replace_first("res://", "game/");
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 1dddb07990..44ab075816 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -35,7 +35,6 @@
#include "core/io/marshalls.h"
#include "core/project_settings.h"
-#include "drivers/gles2/rasterizer_gles2.h"
#include "drivers/unix/ip_unix.h"
#include "drivers/windows/dir_access_windows.h"
#include "drivers/windows/file_access_windows.h"
@@ -297,7 +296,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
void OS_UWP::set_clipboard(const String &p_text) {
DataPackage ^ clip = ref new DataPackage();
clip->RequestedOperation = DataPackageOperation::Copy;
- clip->SetText(ref new Platform::String((const wchar_t *)p_text.c_str()));
+ clip->SetText(ref new Platform::String((LPCWSTR)(p_text.utf16().get_data())));
Clipboard::SetContent(clip);
};
@@ -347,8 +346,8 @@ void OS_UWP::finalize_core() {
}
void OS_UWP::alert(const String &p_alert, const String &p_title) {
- Platform::String ^ alert = ref new Platform::String(p_alert.c_str());
- Platform::String ^ title = ref new Platform::String(p_title.c_str());
+ Platform::String ^ alert = ref new Platform::String((LPCWSTR)(p_alert.utf16().get_data()));
+ Platform::String ^ title = ref new Platform::String((LPCWSTR)(p_title.utf16().get_data()));
MessageDialog ^ msg = ref new MessageDialog(alert, title);
@@ -739,7 +738,7 @@ static String format_error_message(DWORD id) {
Error OS_UWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
String full_path = "game/" + p_path;
- p_library_handle = (void *)LoadPackagedLibrary(full_path.c_str(), 0);
+ p_library_handle = (void *)LoadPackagedLibrary((LPCWSTR)(full_path.utf16().get_data()), 0);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + full_path + ", error: " + format_error_message(GetLastError()) + ".");
return OK;
}
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index 996d9722f5..02031ef6bb 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -175,7 +175,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
msg = proj_settings->get("debug/settings/crash_handler/message");
}
- fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
int n = 0;
do {
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 271ffc8871..4e1da22bb0 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -65,6 +65,7 @@ def get_opts():
# Vista support dropped after EOL due to GH-10243
("target_win_version", "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601"),
EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
+ EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("console", "gui")),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
("msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", None),
BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed. Only used on Windows.", False),
@@ -177,13 +178,14 @@ def configure_msvc(env, manual_msvc_config):
"""Configure env to work with MSVC"""
# Build type
+ if env["tests"]:
+ env["windows_subsystem"] = "console"
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["/O2"])
else: # optimize for size
env.Append(CCFLAGS=["/O1"])
- env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"])
env.Append(LINKFLAGS=["/OPT:REF"])
@@ -193,19 +195,22 @@ def configure_msvc(env, manual_msvc_config):
else: # optimize for size
env.Append(CCFLAGS=["/O1"])
env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
- env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
env.Append(LINKFLAGS=["/OPT:REF"])
elif env["target"] == "debug":
env.AppendUnique(CCFLAGS=["/Z7", "/Od", "/EHsc"])
env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
- env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
env.Append(LINKFLAGS=["/DEBUG"])
if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
env.AppendUnique(CCFLAGS=["/Z7"])
env.AppendUnique(LINKFLAGS=["/DEBUG"])
+ if env["windows_subsystem"] == "gui":
+ env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
+ else:
+ env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
+
## Compile/link flags
env.AppendUnique(CCFLAGS=["/MT", "/Gd", "/GR", "/nologo"])
@@ -303,6 +308,9 @@ def configure_mingw(env):
## Build type
+ if env["tests"]:
+ env["windows_subsystem"] = "console"
+
if env["target"] == "release":
env.Append(CCFLAGS=["-msse2"])
@@ -314,8 +322,6 @@ def configure_mingw(env):
else: # optimize for size
env.Prepend(CCFLAGS=["-Os"])
- env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
-
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
@@ -337,6 +343,11 @@ def configure_mingw(env):
env.Append(CCFLAGS=["-g3"])
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ if env["windows_subsystem"] == "gui":
+ env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
+ else:
+ env.Append(LINKFLAGS=["-Wl,--subsystem,console"])
+
## Compiler configuration
if os.name != "nt":
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index da2fc1c2c1..7f4669b3b2 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -42,7 +42,7 @@ static String format_error_message(DWORD id) {
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
- String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
+ String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size);
LocalFree(messageBuffer);
@@ -78,7 +78,7 @@ String DisplayServerWindows::get_name() const {
}
void DisplayServerWindows::alert(const String &p_alert, const String &p_title) {
- MessageBoxW(nullptr, p_alert.c_str(), p_title.c_str(), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
+ MessageBoxW(nullptr, (LPCWSTR)(p_alert.utf16().get_data()), (LPCWSTR)(p_title.utf16().get_data()), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
}
void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
@@ -177,11 +177,12 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
}
EmptyClipboard();
- HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(CharType));
+ Char16String utf16 = text.utf16();
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (utf16.length() + 1) * sizeof(WCHAR));
ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
- memcpy(lptstrCopy, text.c_str(), (text.length() + 1) * sizeof(CharType));
+ memcpy(lptstrCopy, utf16.get_data(), (utf16.length() + 1) * sizeof(WCHAR));
GlobalUnlock(mem);
SetClipboardData(CF_UNICODETEXT, mem);
@@ -218,7 +219,7 @@ String DisplayServerWindows::clipboard_get() const {
if (mem != nullptr) {
LPWSTR ptr = (LPWSTR)GlobalLock(mem);
if (ptr != nullptr) {
- ret = String((CharType *)ptr);
+ ret = String::utf16((const char16_t *)ptr);
GlobalUnlock(mem);
};
};
@@ -493,14 +494,16 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
wd.no_focus = true;
}
- _update_window_style(window_id);
-
return window_id;
}
void DisplayServerWindows::show_window(WindowID p_id) {
WindowData &wd = windows[p_id];
+ if (p_id != MAIN_WINDOW_ID) {
+ _update_window_style(p_id);
+ }
+
ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window
if (!wd.no_focus) {
SetForegroundWindow(wd.hWnd); // Slightly Higher Priority
@@ -591,7 +594,7 @@ void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_wi
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_window));
- SetWindowTextW(windows[p_window].hWnd, p_title.c_str());
+ SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data()));
}
int DisplayServerWindows::window_get_current_screen(WindowID p_window) const {
@@ -1421,13 +1424,13 @@ String DisplayServerWindows::keyboard_get_layout_language(int p_index) const {
HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
GetKeyboardLayoutList(layout_count, layouts);
- wchar_t buf[LOCALE_NAME_MAX_LENGTH];
- memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t));
+ WCHAR buf[LOCALE_NAME_MAX_LENGTH];
+ memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR));
LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0);
memfree(layouts);
- return String(buf).substr(0, 2);
+ return String::utf16((const char16_t *)buf).substr(0, 2);
}
String _get_full_layout_name_from_registry(HKL p_layout) {
@@ -1435,17 +1438,17 @@ String _get_full_layout_name_from_registry(HKL p_layout) {
String ret;
HKEY hkey;
- wchar_t layout_text[1024];
- memset(layout_text, 0, 1024 * sizeof(wchar_t));
+ WCHAR layout_text[1024];
+ memset(layout_text, 0, 1024 * sizeof(WCHAR));
- if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)id.c_str(), 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) {
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)(id.utf16().get_data()), 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) {
return ret;
}
DWORD buffer = 1024;
DWORD vtype = REG_SZ;
if (RegQueryValueExW(hkey, L"Layout Text", NULL, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) {
- ret = String(layout_text);
+ ret = String::utf16((const char16_t *)layout_text);
}
RegCloseKey(hkey);
return ret;
@@ -1461,15 +1464,15 @@ String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
String ret = _get_full_layout_name_from_registry(layouts[p_index]); // Try reading full name from Windows registry, fallback to locale name if failed (e.g. on Wine).
if (ret == String()) {
- wchar_t buf[LOCALE_NAME_MAX_LENGTH];
- memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t));
+ WCHAR buf[LOCALE_NAME_MAX_LENGTH];
+ memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR));
LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0);
- wchar_t name[1024];
- memset(name, 0, 1024 * sizeof(wchar_t));
+ WCHAR name[1024];
+ memset(name, 0, 1024 * sizeof(WCHAR));
GetLocaleInfoEx(buf, LOCALE_SLOCALIZEDDISPLAYNAME, (LPWSTR)&name, 1024);
- ret = String(name);
+ ret = String::utf16((const char16_t *)name);
}
memfree(layouts);
@@ -2030,8 +2033,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Ref<InputEventMouseMotion> mm;
mm.instance();
mm->set_window_id(window_id);
- mm->set_control(GetKeyState(VK_CONTROL) != 0);
- mm->set_shift(GetKeyState(VK_SHIFT) != 0);
+ mm->set_control(GetKeyState(VK_CONTROL) < 0);
+ mm->set_shift(GetKeyState(VK_SHIFT) < 0);
mm->set_alt(alt_mem);
mm->set_pressure(windows[window_id].last_pressure);
@@ -2173,8 +2176,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_tilt(Vector2((float)pen_info.tiltX / 90, (float)pen_info.tiltY / 90));
}
- mm->set_control((wParam & MK_CONTROL) != 0);
- mm->set_shift((wParam & MK_SHIFT) != 0);
+ mm->set_control(GetKeyState(VK_CONTROL) < 0);
+ mm->set_shift(GetKeyState(VK_SHIFT) < 0);
mm->set_alt(alt_mem);
mm->set_button_mask(last_button_state);
@@ -2709,7 +2712,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_DROPFILES: {
HDROP hDropInfo = (HDROP)wParam;
const int buffsize = 4096;
- wchar_t buf[buffsize];
+ WCHAR buf[buffsize];
int fcount = DragQueryFileW(hDropInfo, 0xFFFFFFFF, nullptr, 0);
@@ -2717,7 +2720,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
for (int i = 0; i < fcount; i++) {
DragQueryFileW(hDropInfo, i, buf, buffsize);
- String file = buf;
+ String file = String::utf16((const char16_t *)buf);
files.push_back(file);
}
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 5b15896b0c..f73516b370 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -84,7 +84,7 @@ static String format_error_message(DWORD id) {
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
- String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
+ String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size);
LocalFree(messageBuffer);
@@ -107,15 +107,11 @@ void RedirectIOToConsole() {
// set the screen buffer to be big enough to let us scroll text
- GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
-
- &coninfo);
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
coninfo.dwSize.Y = MAX_CONSOLE_LINES;
- SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
-
- coninfo.dwSize);
+ SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
// redirect unbuffered STDOUT to the console
@@ -265,10 +261,10 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
DLL_DIRECTORY_COOKIE cookie = nullptr;
if (p_also_set_library_path && has_dll_directory_api) {
- cookie = add_dll_directory(path.get_base_dir().c_str());
+ cookie = add_dll_directory((LPCWSTR)(path.get_base_dir().utf16().get_data()));
}
- p_library_handle = (void *)LoadLibraryExW(path.c_str(), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
+ p_library_handle = (void *)LoadLibraryExW((LPCWSTR)(path.utf16().get_data()), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + format_error_message(GetLastError()) + ".");
if (cookie) {
@@ -407,7 +403,7 @@ uint64_t OS_Windows::get_ticks_usec() const {
String OS_Windows::_quote_command_line_argument(const String &p_text) const {
for (int i = 0; i < p_text.size(); i++) {
- CharType c = p_text[i];
+ char32_t c = p_text[i];
if (c == ' ' || c == '&' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '=' || c == ';' || c == '!' || c == '\'' || c == '+' || c == ',' || c == '`' || c == '~') {
return "\"" + p_text + "\"";
}
@@ -428,7 +424,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
// Note: _wpopen is calling command as "cmd.exe /c argss", instead of executing it directly, add extra quotes around full command, to prevent it from stripping quotes in the command.
argss = _quote_command_line_argument(argss);
- FILE *f = _wpopen(argss.c_str(), L"r");
+ FILE *f = _wpopen((LPCWSTR)(argss.utf16().get_data()), L"r");
ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
char buf[65535];
@@ -463,13 +459,8 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
ZeroMemory(&pi.pi, sizeof(pi.pi));
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
- Vector<CharType> modstr; // Windows wants to change this no idea why.
- modstr.resize(cmdline.size());
- for (int i = 0; i < cmdline.size(); i++) {
- modstr.write[i] = cmdline[i];
- }
-
- int ret = CreateProcessW(nullptr, modstr.ptrw(), nullptr, nullptr, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
+ Char16String modstr = cmdline.utf16(); // Windows wants to change this no idea why.
+ int ret = CreateProcessW(nullptr, (LPWSTR)(modstr.ptrw()), nullptr, nullptr, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
if (p_blocking) {
@@ -509,26 +500,26 @@ int OS_Windows::get_process_id() const {
}
Error OS_Windows::set_cwd(const String &p_cwd) {
- if (_wchdir(p_cwd.c_str()) != 0)
+ if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0)
return ERR_CANT_OPEN;
return OK;
}
String OS_Windows::get_executable_path() const {
- wchar_t bufname[4096];
+ WCHAR bufname[4096];
GetModuleFileNameW(nullptr, bufname, 4096);
- String s = bufname;
+ String s = String::utf16((const char16_t *)bufname);
return s;
}
bool OS_Windows::has_environment(const String &p_var) const {
#ifdef MINGW_ENABLED
- return _wgetenv(p_var.c_str()) != nullptr;
+ return _wgetenv((LPCWSTR)(p_var.utf16().get_data())) != nullptr;
#else
- wchar_t *env;
+ WCHAR *env;
size_t len;
- _wdupenv_s(&env, &len, p_var.c_str());
+ _wdupenv_s(&env, &len, (LPCWSTR)(p_var.utf16().get_data()));
const bool has_env = env != nullptr;
free(env);
return has_env;
@@ -536,16 +527,16 @@ bool OS_Windows::has_environment(const String &p_var) const {
};
String OS_Windows::get_environment(const String &p_var) const {
- wchar_t wval[0x7Fff]; // MSDN says 32767 char is the maximum
- int wlen = GetEnvironmentVariableW(p_var.c_str(), wval, 0x7Fff);
+ WCHAR wval[0x7fff]; // MSDN says 32767 char is the maximum
+ int wlen = GetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), wval, 0x7fff);
if (wlen > 0) {
- return wval;
+ return String::utf16((const char16_t *)wval);
}
return "";
}
bool OS_Windows::set_environment(const String &p_var, const String &p_value) const {
- return (bool)SetEnvironmentVariableW(p_var.c_str(), p_value.c_str());
+ return (bool)SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), (LPCWSTR)(p_value.utf16().get_data()));
}
String OS_Windows::get_stdin_string(bool p_block) {
@@ -558,7 +549,7 @@ String OS_Windows::get_stdin_string(bool p_block) {
}
Error OS_Windows::shell_open(String p_uri) {
- ShellExecuteW(nullptr, nullptr, p_uri.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL);
return OK;
}
@@ -701,7 +692,7 @@ String OS_Windows::get_system_dir(SystemDir p_dir) const {
PWSTR szPath;
HRESULT res = SHGetKnownFolderPath(id, 0, nullptr, &szPath);
ERR_FAIL_COND_V(res != S_OK, String());
- String path = String(szPath);
+ String path = String::utf16((const char16_t *)szPath);
CoTaskMemFree(szPath);
return path;
}
@@ -727,7 +718,7 @@ String OS_Windows::get_user_data_dir() const {
String OS_Windows::get_unique_id() const {
HW_PROFILE_INFO HwProfInfo;
ERR_FAIL_COND_V(!GetCurrentHwProfile(&HwProfInfo), "");
- return String(HwProfInfo.szHwProfileGuid);
+ return String::utf16((const char16_t *)(HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN);
}
bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
@@ -744,9 +735,11 @@ bool OS_Windows::is_disable_crash_handler() const {
Error OS_Windows::move_to_trash(const String &p_path) {
SHFILEOPSTRUCTW sf;
- WCHAR *from = new WCHAR[p_path.length() + 2];
- wcscpy_s(from, p_path.length() + 1, p_path.c_str());
- from[p_path.length() + 1] = 0;
+
+ Char16String utf16 = p_path.utf16();
+ WCHAR *from = new WCHAR[utf16.length() + 2];
+ wcscpy_s(from, utf16.length() + 1, (LPCWSTR)(utf16.get_data()));
+ from[utf16.length() + 1] = 0;
sf.hwnd = main_window;
sf.wFunc = FO_DELETE;
diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h
index 290decac5f..09a16614e0 100644
--- a/platform/windows/platform_config.h
+++ b/platform/windows/platform_config.h
@@ -29,5 +29,3 @@
/*************************************************************************/
#include <malloc.h>
-
-#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h"