diff options
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/export/export.cpp | 203 | ||||
-rw-r--r-- | platform/android/java_class_wrapper.cpp | 2 | ||||
-rw-r--r-- | platform/android/os_android.cpp | 32 | ||||
-rw-r--r-- | platform/android/os_android.h | 1 | ||||
-rw-r--r-- | platform/iphone/SCsub | 12 | ||||
-rw-r--r-- | platform/iphone/detect.py | 19 | ||||
-rw-r--r-- | platform/iphone/export/export.cpp | 453 | ||||
-rw-r--r-- | platform/iphone/game_center.mm | 14 | ||||
-rw-r--r-- | platform/iphone/os_iphone.cpp | 78 | ||||
-rw-r--r-- | platform/iphone/os_iphone.h | 8 | ||||
-rw-r--r-- | platform/javascript/export/export.cpp | 5 | ||||
-rw-r--r-- | platform/javascript/os_javascript.cpp | 4 | ||||
-rw-r--r-- | platform/javascript/os_javascript.h | 1 | ||||
-rw-r--r-- | platform/osx/export/export.cpp | 3 | ||||
-rw-r--r-- | platform/osx/os_osx.h | 1 | ||||
-rw-r--r-- | platform/osx/os_osx.mm | 67 | ||||
-rw-r--r-- | platform/uwp/export/export.cpp | 24 | ||||
-rw-r--r-- | platform/uwp/os_uwp.cpp | 13 | ||||
-rw-r--r-- | platform/uwp/os_uwp.h | 1 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 15 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 1 | ||||
-rw-r--r-- | platform/x11/os_x11.cpp | 84 | ||||
-rw-r--r-- | platform/x11/os_x11.h | 3 |
23 files changed, 750 insertions, 294 deletions
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index e1ff12c5ac..67e00f4952 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -192,6 +192,19 @@ static const char *android_perms[] = { NULL }; +struct LauncherIcon { + char *option_id; + char *export_path; +}; + +static const LauncherIcon launcher_icons[] = { + { "launcher_icons/xxxhdpi_192x192", "res/drawable-xxxhdpi-v4/icon.png" }, + { "launcher_icons/xxhdpi_144x144", "res/drawable-xxhdpi-v4/icon.png" }, + { "launcher_icons/xhdpi_96x96", "res/drawable-xhdpi-v4/icon.png" }, + { "launcher_icons/hdpi_72x72", "res/drawable-hdpi-v4/icon.png" }, + { "launcher_icons/mdpi_48x48", "res/drawable-mdpi-v4/icon.png" } +}; + class EditorExportAndroid : public EditorExportPlatform { GDCLASS(EditorExportAndroid, EditorExportPlatform) @@ -467,52 +480,72 @@ class EditorExportAndroid : public EditorExportPlatform { return zipfi; } - static Set<String> get_abis() { - Set<String> abis; - abis.insert("armeabi"); - abis.insert("armeabi-v7a"); - abis.insert("arm64-v8a"); - abis.insert("x86"); - abis.insert("x86_64"); - abis.insert("mips"); - abis.insert("mips64"); + static Vector<String> get_abis() { + // mips and armv6 are dead (especially for games), so not including them + Vector<String> abis; + abis.push_back("armeabi-v7a"); + abis.push_back("arm64-v8a"); + abis.push_back("x86"); + abis.push_back("x86_64"); return abis; } - static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) { - APKExportData *ed = (APKExportData *)p_userdata; - String dst_path = p_path; - static Set<String> android_abis = get_abis(); - - if (dst_path.ends_with(".so")) { - String abi = dst_path.get_base_dir().get_file().strip_edges(); // parent dir name - if (android_abis.has(abi)) { - dst_path = "lib/" + abi + "/" + dst_path.get_file(); - } else { - String err = "Dynamic libraries must be located in the folder named after Android ABI they were compiled for. " + - p_path + " does not follow this convention."; - ERR_PRINT(err.utf8().get_data()); - return ERR_FILE_BAD_PATH; - } - } else { - dst_path = dst_path.replace_first("res://", "assets/"); - } - + static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED) { zip_fileinfo zipfi = get_zip_fileinfo(); - zipOpenNewFileInZip(ed->apk, - dst_path.utf8().get_data(), + p_path.utf8().get_data(), &zipfi, NULL, 0, NULL, 0, NULL, - _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0, + compression_method, Z_DEFAULT_COMPRESSION); zipWriteInFileInZip(ed->apk, p_data.ptr(), p_data.size()); zipCloseFileInZip(ed->apk); + + return OK; + } + + static Error save_apk_so(void *p_userdata, const SharedObject &p_so) { + if (!p_so.path.get_file().begins_with("lib")) { + String err = "Android .so file names must start with \"lib\", but got: " + p_so.path; + ERR_PRINT(err.utf8().get_data()); + return FAILED; + } + APKExportData *ed = (APKExportData *)p_userdata; + Vector<String> abis = get_abis(); + bool exported = false; + for (int i = 0; i < p_so.tags.size(); ++i) { + // shared objects can be fat (compatible with multiple ABIs) + int start_pos = 0; + int abi_index = abis.find(p_so.tags[i]); + if (abi_index != -1) { + exported = true; + start_pos = abi_index + 1; + String abi = abis[abi_index]; + String dst_path = "lib/" + abi + "/" + p_so.path.get_file(); + Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path); + Error store_err = store_in_apk(ed, dst_path, array); + ERR_FAIL_COND_V(store_err, store_err); + } + } + if (!exported) { + String abis_string = String(" ").join(abis); + String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string; + ERR_PRINT(err.utf8().get_data()); + return FAILED; + } + 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) { + APKExportData *ed = (APKExportData *)p_userdata; + String dst_path = p_path.replace_first("res://", "assets/"); + + store_in_apk(ed, dst_path, p_data, _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0); ed->ep->step("File: " + p_path, 3 + p_file * 100 / p_total); return OK; } @@ -935,6 +968,18 @@ class EditorExportAndroid : public EditorExportPlatform { //printf("end\n"); } + static Vector<String> get_enabled_abis(const Ref<EditorExportPreset> &p_preset) { + Vector<String> abis = get_abis(); + Vector<String> enabled_abis; + for (int i = 0; i < abis.size(); ++i) { + bool is_enabled = p_preset->get("architectures/" + abis[i]); + if (is_enabled) { + enabled_abis.push_back(abis[i]); + } + } + return enabled_abis; + } + public: enum { MAX_USER_PERMISSIONS = 20 @@ -951,6 +996,11 @@ public: r_features->push_back("etc"); else*/ r_features->push_back("etc2"); + + Vector<String> abis = get_enabled_abis(p_preset); + for (int i = 0; i < abis.size(); ++i) { + r_features->push_back(abis[i]); + } } virtual void get_export_options(List<ExportOption> *r_options) { @@ -965,16 +1015,18 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name"), "org.godotengine.$genname")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/icon", PROPERTY_HINT_FILE, "png"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architecture/arm"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architecture/x86"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "screen/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_normal"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true)); + + for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icons[i].option_id, PROPERTY_HINT_FILE, "png"), "")); + } + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "keystore"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), "")); @@ -982,6 +1034,13 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/SALT"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT), "")); + Vector<String> abis = get_abis(); + for (int i = 0; i < abis.size(); ++i) { + String abi = abis[i]; + bool is_default = (abi == "armeabi-v7a"); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default)); + } + const char **perms = android_perms; while (*perms) { @@ -1295,10 +1354,6 @@ public: String unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned.apk"); zipFile unaligned_apk = zipOpen2(unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); - bool export_x86 = p_preset->get("architecture/x86"); - bool export_arm = p_preset->get("architecture/arm"); - bool export_arm64 = p_preset->get("architecture/arm64"); - bool use_32_fb = p_preset->get("graphics/32_bits_framebuffer"); bool immersive = p_preset->get("screen/immersive_mode"); @@ -1318,6 +1373,8 @@ public: String release_username = p_preset->get("keystore/release_user"); String release_password = p_preset->get("keystore/release_password"); + Vector<String> enabled_abis = get_enabled_abis(p_preset); + while (ret == UNZ_OK) { //get filename @@ -1334,7 +1391,7 @@ public: //read unzOpenCurrentFile(pkg); - unzReadCurrentFile(pkg, data.ptr(), data.size()); + unzReadCurrentFile(pkg, data.ptrw(), data.size()); unzCloseCurrentFile(pkg); //write @@ -1350,23 +1407,20 @@ public: } if (file == "res/drawable/icon.png") { - - String icon = p_preset->get("package/icon"); - icon = icon.strip_edges(); bool found = false; - - if (icon != "" && icon.ends_with(".png")) { - - FileAccess *f = FileAccess::open(icon, FileAccess::READ); - if (f) { - - data.resize(f->get_len()); - f->get_buffer(data.ptr(), data.size()); - memdelete(f); - found = true; + for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { + String icon_path = String(p_preset->get(launcher_icons[i].option_id)).strip_edges(); + if (icon_path != "" && icon_path.ends_with(".png")) { + FileAccess *f = FileAccess::open(icon_path, FileAccess::READ); + if (f) { + data.resize(f->get_len()); + f->get_buffer(data.ptrw(), data.size()); + memdelete(f); + found = true; + break; + } } } - if (!found) { String appicon = ProjectSettings::get_singleton()->get("application/config/icon"); @@ -1374,32 +1428,32 @@ public: FileAccess *f = FileAccess::open(appicon, FileAccess::READ); if (f) { data.resize(f->get_len()); - f->get_buffer(data.ptr(), data.size()); + f->get_buffer(data.ptrw(), data.size()); memdelete(f); } } } } - if (file == "lib/x86/*.so" && !export_x86) { - skip = true; - } - - if (file.match("lib/armeabi*/*.so") && !export_arm) { - skip = true; - } - - if (file.match("lib/arm64*/*.so") && !export_arm64) { - skip = true; + if (file.ends_with(".so")) { + bool enabled = false; + for (int i = 0; i < enabled_abis.size(); ++i) { + if (file.begins_with("lib/" + enabled_abis[i] + "/")) { + enabled = true; + break; + } + } + if (!enabled) { + skip = true; + } } if (file.begins_with("META-INF") && _signed) { skip = true; } - print_line("ADDING: " + file); - if (!skip) { + print_line("ADDING: " + file); // Respect decision on compression made by AAPT for the export template const bool uncompressed = info.compression_method == 0; @@ -1473,7 +1527,20 @@ public: ed.ep = &ep; ed.apk = unaligned_apk; - err = export_project_files(p_preset, save_apk_file, &ed); + err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so); + } + + if (!err) { + APKExportData ed; + ed.ep = &ep; + ed.apk = unaligned_apk; + for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) { + String icon_path = String(p_preset->get(launcher_icons[i].option_id)).strip_edges(); + if (icon_path != "" && icon_path.ends_with(".png") && FileAccess::exists(icon_path)) { + Vector<uint8_t> data = FileAccess::get_file_as_array(icon_path); + store_in_apk(&ed, launcher_icons[i].export_path, data); + } + } } } @@ -1636,7 +1703,7 @@ public: int method, level; unzOpenCurrentFile2(tmp_unaligned, &method, &level, 1); // raw read long file_offset = unzGetCurrentFileZStreamPos64(tmp_unaligned); - unzReadCurrentFile(tmp_unaligned, data.ptr(), data.size()); + unzReadCurrentFile(tmp_unaligned, data.ptrw(), data.size()); unzCloseCurrentFile(tmp_unaligned); // align diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp index 8606ea41a0..892e64cdfc 100644 --- a/platform/android/java_class_wrapper.cpp +++ b/platform/android/java_class_wrapper.cpp @@ -59,7 +59,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, r_error.argument = pc; continue; } - uint32_t *ptypes = E->get().param_types.ptr(); + uint32_t *ptypes = E->get().param_types.ptrw(); bool valid = true; for (int i = 0; i < pc; i++) { diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index d5ccf76631..b575f15559 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -114,15 +114,6 @@ void OS_Android::initialize_core() { #endif } -void OS_Android::initialize_logger() { - Vector<Logger *> loggers; - loggers.push_back(memnew(AndroidLogger)); - // FIXME: Reenable once we figure out how to get this properly in user:// - // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) - //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); - _set_logger(memnew(CompositeLogger(loggers))); -} - void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { ERR_FAIL_COND(!p_gl_extensions); @@ -705,7 +696,24 @@ String OS_Android::get_joy_guid(int p_device) const { } bool OS_Android::_check_internal_feature_support(const String &p_feature) { - return p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2"; //TODO support etc2 only if GLES3 driver is selected + if (p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2") { + //TODO support etc2 only if GLES3 driver is selected + return true; + } +#if defined(__aarch64__) + if (p_feature == "arm64-v8a") { + return true; + } +#elif defined(__ARM_ARCH_7A__) + if (p_feature == "armeabi-v7a" || p_feature == "armeabi") { + return true; + } +#elif defined(__arm__) + if (p_feature == "armeabi") { + return true; + } +#endif + return false; } OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { @@ -745,7 +753,9 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI alert_func = p_alert_func; use_reload_hooks = false; - _set_logger(memnew(AndroidLogger)); + Vector<Logger *> loggers; + loggers.push_back(memnew(AndroidLogger)); + _set_logger(memnew(CompositeLogger(loggers))); } OS_Android::~OS_Android() { diff --git a/platform/android/os_android.h b/platform/android/os_android.h index d25f60d540..3b7f55096e 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -144,7 +144,6 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; - virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index 61798c5f87..550dfdd7d6 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -3,7 +3,7 @@ Import('env') iphone_lib = [ - + 'godot_iphone.cpp', 'os_iphone.cpp', 'sem_iphone.cpp', 'gl_view.mm', @@ -17,10 +17,10 @@ iphone_lib = [ ] env_ios = env.Clone() +ios_lib = env_ios.Library('iphone', iphone_lib) -obj = env_ios.Object('godot_iphone.cpp') +def combine_libs(target=None, source=None, env=None): + lib_path = target[0].srcnode().abspath + env.Execute('$IPHONEPATH/usr/bin/libtool -static -o "' + lib_path + '" ' + ' '.join([('"' + lib.srcnode().abspath + '"') for lib in source])) -prog = None -prog = env_ios.Program('#bin/godot', [obj] + iphone_lib) -action = "$IPHONEPATH/usr/bin/dsymutil " + File(prog)[0].path + " -o " + File(prog)[0].path + ".dSYM" -env.AddPostAction(prog, action) +combine_command = env_ios.Command('#bin/libgodot' + env_ios['LIBSUFFIX'], [ios_lib] + env_ios['LIBS'], combine_libs) diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index 4ea358f871..25674c2b47 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -61,10 +61,13 @@ def configure(env): env.Append(LINKFLAGS=['-flto']) ## Architecture + if env["ios_sim"] and not ("arch" in env): + env["arch"] = "x86" - if env["ios_sim"] or env["arch"] == "x86": # i386, simulator - env["arch"] = "x86" + if env["arch"] == "x86": # i386, simulator env["bits"] = "32" + elif env["arch"] == "x86_64": + env["bits"] = "64" elif (env["arch"] == "arm" or env["arch"] == "arm32" or env["arch"] == "armv7" or env["bits"] == "32"): # arm env["arch"] = "arm" env["bits"] = "32" @@ -95,10 +98,11 @@ def configure(env): ## Compile flags - if (env["arch"] == "x86"): + if (env["arch"] == "x86" or env["arch"] == "x86_64"): env['IPHONEPLATFORM'] = 'iPhoneSimulator' - env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6' - env.Append(CCFLAGS='-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $IPHONESDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"'.split()) + env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.9' + arch_flag = "i386" if env["arch"] == "x86" else env["arch"] + env.Append(CCFLAGS=('-arch ' + arch_flag + ' -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=9.0 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"').split()) elif (env["arch"] == "arm"): env.Append(CCFLAGS='-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=9.0 -MMD -MT dependencies'.split()) elif (env["arch"] == "arm64"): @@ -113,8 +117,9 @@ def configure(env): ## Link flags - if (env["arch"] == "x86"): - env.Append(LINKFLAGS=['-arch', 'i386', '-mios-simulator-version-min=4.3', + if (env["arch"] == "x86" or env["arch"] == "x86_64"): + arch_flag = "i386" if env["arch"] == "x86" else env["arch"] + env.Append(LINKFLAGS=['-arch', arch_flag, '-mios-simulator-version-min=9.0', '-isysroot', '$IPHONESDK', '-Xlinker', '-objc_abi_version', diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 0507ef19d6..8ab1cbc435 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -56,11 +56,48 @@ class EditorExportPlatformIOS : public EditorExportPlatform { static Error _walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata); static Error _codesign(String p_file, void *p_userdata); - void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const String &p_name, const String &p_binary, bool p_debug); - static Error _export_dylibs(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total); + struct IOSConfigData { + String pkg_name; + String binary_name; + String plist_content; + String architectures; + String linker_flags; + String cpp_code; + }; + + struct ExportArchitecture { + String name; + bool is_default; + + ExportArchitecture() + : name(""), is_default(false) { + } + + ExportArchitecture(String p_name, bool p_is_default) { + name = p_name; + is_default = p_is_default; + } + }; + + struct IOSExportAsset { + String exported_path; + bool is_framework; // framework is anything linked to the binary, otherwise it's a resource + }; + + String _get_additional_plist_content(); + String _get_linker_flags(); + String _get_cpp_code(); + void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug); Error _export_loading_screens(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir); Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir); + Vector<ExportArchitecture> _get_supported_architectures(); + Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset); + + void _add_assets_to_project(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<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets); + protected: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features); virtual void get_export_options(List<ExportOption> *r_options); @@ -96,6 +133,17 @@ void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> if (p_preset->get("texture_format/etc2")) { r_features->push_back("etc2"); } + Vector<String> architectures = _get_preset_architectures(p_preset); + for (int i = 0; i < architectures.size(); ++i) { + r_features->push_back(architectures[i]); + } +} + +Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_get_supported_architectures() { + Vector<ExportArchitecture> archs; + archs.push_back(ExportArchitecture("armv7", true)); + archs.push_back(ExportArchitecture("arm64", true)); + return archs; } void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) { @@ -120,7 +168,6 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/iphone_120x120", PROPERTY_HINT_FILE, "png"), "")); // Home screen on iPhone/iPod Touch with retina display r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/ipad_76x76", PROPERTY_HINT_FILE, "png"), "")); // Home screen on iPad @@ -145,10 +192,13 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), true)); - /* probably need some more info */ + Vector<ExportArchitecture> architectures = _get_supported_architectures(); + for (int i = 0; i < architectures.size(); ++i) { + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + architectures[i].name), architectures[i].is_default)); + } } -void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const String &p_name, const String &p_binary, bool p_debug) { +void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug) { static const String export_method_string[] = { "app-store", "development", @@ -158,13 +208,12 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ String str; String strnew; str.parse_utf8((const char *)pfile.ptr(), pfile.size()); - print_line(str); Vector<String> lines = str.split("\n"); for (int i = 0; i < lines.size(); i++) { if (lines[i].find("$binary") != -1) { - strnew += lines[i].replace("$binary", p_binary) + "\n"; + strnew += lines[i].replace("$binary", p_config.binary_name) + "\n"; } else if (lines[i].find("$name") != -1) { - strnew += lines[i].replace("$name", p_name) + "\n"; + strnew += lines[i].replace("$name", p_config.pkg_name) + "\n"; } else if (lines[i].find("$info") != -1) { strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n"; } else if (lines[i].find("$identifier") != -1) { @@ -186,10 +235,21 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get("application/provisioning_profile_uuid_release")) + "\n"; } else if (lines[i].find("$provisioning_profile_uuid_debug") != -1) { strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get("application/provisioning_profile_uuid_debug")) + "\n"; + } else if (lines[i].find("$provisioning_profile_uuid") != -1) { + String uuid = p_debug ? p_preset->get("application/provisioning_profile_uuid_debug") : p_preset->get("application/provisioning_profile_uuid_release"); + strnew += lines[i].replace("$provisioning_profile_uuid", uuid) + "\n"; } else if (lines[i].find("$code_sign_identity_debug") != -1) { strnew += lines[i].replace("$code_sign_identity_debug", p_preset->get("application/code_sign_identity_debug")) + "\n"; } else if (lines[i].find("$code_sign_identity_release") != -1) { strnew += lines[i].replace("$code_sign_identity_release", p_preset->get("application/code_sign_identity_release")) + "\n"; + } else if (lines[i].find("$additional_plist_content") != -1) { + strnew += lines[i].replace("$additional_plist_content", p_config.plist_content) + "\n"; + } else if (lines[i].find("$godot_archs") != -1) { + strnew += lines[i].replace("$godot_archs", p_config.architectures) + "\n"; + } else if (lines[i].find("$linker_flags") != -1) { + strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n"; + } else if (lines[i].find("$cpp_code") != -1) { + strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n"; } else { strnew += lines[i] + "\n"; } @@ -204,27 +264,37 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ } } -Error EditorExportPlatformIOS::_export_dylibs(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) { - if (!p_path.ends_with(".dylib")) return OK; - const String &dest_dir = *(String *)p_userdata; - String rel_path = p_path.replace_first("res://", "dylibs/"); - DirAccess *dest_dir_access = DirAccess::open(dest_dir); - ERR_FAIL_COND_V(!dest_dir_access, ERR_CANT_OPEN); - - String base_dir = rel_path.get_base_dir(); - Error make_dir_err = OK; - if (!dest_dir_access->dir_exists(base_dir)) { - make_dir_err = dest_dir_access->make_dir_recursive(base_dir); - } - if (make_dir_err != OK) { - memdelete(dest_dir_access); - return make_dir_err; +String EditorExportPlatformIOS::_get_additional_plist_content() { + Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins(); + String result; + for (int i = 0; i < export_plugins.size(); ++i) { + result += export_plugins[i]->get_ios_plist_content(); } + return result; +} - Error copy_err = dest_dir_access->copy(p_path, dest_dir + rel_path); - memdelete(dest_dir_access); +String EditorExportPlatformIOS::_get_linker_flags() { + Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins(); + String result; + for (int i = 0; i < export_plugins.size(); ++i) { + String flags = export_plugins[i]->get_ios_linker_flags(); + if (flags.length() == 0) continue; + if (result.length() > 0) { + result += ' '; + } + result += flags; + } + // the flags will be enclosed in quotes, so need to escape them + return result.replace("\"", "\\\""); +} - return copy_err; +String EditorExportPlatformIOS::_get_cpp_code() { + Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins(); + String result; + for (int i = 0; i < export_plugins.size(); ++i) { + result += export_plugins[i]->get_ios_cpp_code(); + } + return result; } struct IconInfo { @@ -402,7 +472,207 @@ Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) { return OK; } +struct PbxId { +private: + static char _hex_char(uint8_t four_bits) { + if (four_bits < 10) { + return ('0' + four_bits); + } + return 'A' + (four_bits - 10); + } + + static String _hex_pad(uint32_t num) { + Vector<char> ret; + ret.resize(sizeof(num) * 2); + for (int i = 0; i < sizeof(num) * 2; ++i) { + uint8_t four_bits = (num >> (sizeof(num) * 8 - (i + 1) * 4)) & 0xF; + ret[i] = _hex_char(four_bits); + } + return String::utf8(ret.ptr(), ret.size()); + } + +public: + uint32_t high_bits; + uint32_t mid_bits; + uint32_t low_bits; + + String str() const { + return _hex_pad(high_bits) + _hex_pad(mid_bits) + _hex_pad(low_bits); + } + + PbxId &operator++() { + low_bits++; + if (!low_bits) { + mid_bits++; + if (!mid_bits) { + high_bits++; + } + } + + return *this; + } +}; + +struct ExportLibsData { + Vector<String> lib_paths; + String dest_dir; +}; + +void EditorExportPlatformIOS::_add_assets_to_project(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 }; + String pbx_files; + String pbx_frameworks_build; + String pbx_frameworks_refs; + String pbx_resources_build; + String pbx_resources_refs; + + const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") + + "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = $name; path = \"$file_path\"; sourceTree = \"<group>\"; };\n"; + for (int i = 0; i < p_additional_assets.size(); ++i) { + String build_id = (++current_id).str(); + String ref_id = (++current_id).str(); + const IOSExportAsset &asset = p_additional_assets[i]; + + String type; + if (asset.exported_path.ends_with(".framework")) { + type = "wrapper.framework"; + } else if (asset.exported_path.ends_with(".dylib")) { + type = "compiled.mach-o.dylib"; + } else if (asset.exported_path.ends_with(".a")) { + type = "archive.ar"; + } else { + type = "file"; + } + + String &pbx_build = asset.is_framework ? pbx_frameworks_build : pbx_resources_build; + String &pbx_refs = asset.is_framework ? pbx_frameworks_refs : pbx_resources_refs; + + if (pbx_build.length() > 0) { + pbx_build += ",\n"; + pbx_refs += ",\n"; + } + pbx_build += build_id; + pbx_refs += ref_id; + + Dictionary format_dict; + format_dict["build_id"] = build_id; + format_dict["ref_id"] = ref_id; + format_dict["name"] = asset.exported_path.get_file(); + format_dict["file_path"] = asset.exported_path; + format_dict["file_type"] = type; + pbx_files += file_info_format.format(format_dict, "$_"); + } + + String str = String::utf8((const char *)p_project_data.ptr(), p_project_data.size()); + str = str.replace("$additional_pbx_files", pbx_files); + str = str.replace("$additional_pbx_frameworks_build", pbx_frameworks_build); + str = str.replace("$additional_pbx_frameworks_refs", pbx_frameworks_refs); + str = str.replace("$additional_pbx_resources_build", pbx_resources_build); + str = str.replace("$additional_pbx_resources_refs", pbx_resources_refs); + + CharString cs = str.utf8(); + p_project_data.resize(cs.size() - 1); + for (int i = 0; i < cs.size() - 1; i++) { + p_project_data[i] = cs[i]; + } +} + +Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, Vector<IOSExportAsset> &r_exported_assets) { + DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(!filesystem_da, ERR_CANT_CREATE); + for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) { + 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 }; + r_exported_assets.push_back(exported_asset); + } else { + DirAccess *da = DirAccess::create_for_path(asset); + if (!da) { + memdelete(filesystem_da); + ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + } + bool file_exists = da->file_exists(asset); + bool dir_exists = da->dir_exists(asset); + if (!file_exists && !dir_exists) { + memdelete(da); + memdelete(filesystem_da); + return ERR_FILE_NOT_FOUND; + } + String additional_dir = p_is_framework && asset.ends_with(".dylib") ? "/dylibs/" : "/"; + String destination_dir = p_out_dir + additional_dir + asset.get_base_dir().replace("res://", ""); + if (!filesystem_da->dir_exists(destination_dir)) { + Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); + if (make_dir_err) { + memdelete(da); + memdelete(filesystem_da); + return make_dir_err; + } + } + + String destination = destination_dir + "/" + asset.get_file(); + Error err = dir_exists ? da->copy_dir(asset, destination) : da->copy(asset, destination); + memdelete(da); + if (err) { + memdelete(filesystem_da); + return err; + } + IOSExportAsset exported_asset = { destination, p_is_framework }; + r_exported_assets.push_back(exported_asset); + } + } + memdelete(filesystem_da); + + return OK; +} + +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); + 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_FAIL_COND_V(err, err); + } + + Vector<String> library_paths; + 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); + ERR_FAIL_COND_V(err, err); + + return OK; +} + +Vector<String> EditorExportPlatformIOS::_get_preset_architectures(const Ref<EditorExportPreset> &p_preset) { + Vector<ExportArchitecture> all_archs = _get_supported_architectures(); + Vector<String> enabled_archs; + for (int i = 0; i < all_archs.size(); ++i) { + bool is_enabled = p_preset->get("architectures/" + all_archs[i].name); + if (is_enabled) { + enabled_archs.push_back(all_archs[i].name); + } + } + return enabled_archs; +} + Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); + String src_pkg_name; String dest_dir = p_path.get_base_dir() + "/"; String binary_name = p_path.get_file().get_basename(); @@ -427,26 +697,43 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p } } - FileAccess *src_f = NULL; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (da) { + String current_dir = da->get_current_dir(); - ep.step("Creating app", 0); + // remove leftovers from last export so they don't interfere + // in case some files are no longer needed + if (da->change_dir(dest_dir + binary_name + ".xcodeproj") == OK) { + da->erase_contents_recursive(); + } + if (da->change_dir(dest_dir + binary_name) == OK) { + da->erase_contents_recursive(); + } - unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); - if (!src_pkg_zip) { + da->change_dir(current_dir); - EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name); - return ERR_FILE_NOT_FOUND; + if (!da->dir_exists(dest_dir + binary_name)) { + Error err = da->make_dir(dest_dir + binary_name); + if (err) { + memdelete(da); + return err; + } + } + memdelete(da); } - ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN); - int ret = unzGoToFirstFile(src_pkg_zip); + ep.step("Making .pck", 0); + String pack_path = dest_dir + binary_name + ".pck"; + Vector<SharedObject> libraries; + Error err = save_pack(p_preset, pack_path, &libraries); + if (err) + return err; + + ep.step("Extracting and configuring Xcode project", 1); - String binary_to_use = "godot.iphone." + String(p_debug ? "debug" : "release") + "."; - int bits_mode = p_preset->get("application/bits_mode"); - binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "arm64" : "armv7"); + String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".fat.a"; - print_line("binary: " + binary_to_use); + print_line("static library: " + library_to_use); String pkg_name; if (p_preset->get("application/name") != "") pkg_name = p_preset->get("application/name"); // app_name @@ -455,22 +742,41 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p else pkg_name = "Unnamed"; - DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir); - ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE) - - /* Now process our template */ - bool found_binary = false; + bool found_library = false; int total_size = 0; + const String project_file = "godot_ios.xcodeproj/project.pbxproj"; Set<String> files_to_parse; files_to_parse.insert("godot_ios/godot_ios-Info.plist"); - files_to_parse.insert("godot_ios.xcodeproj/project.pbxproj"); - files_to_parse.insert("export_options.plist"); + files_to_parse.insert(project_file); + files_to_parse.insert("godot_ios/export_options.plist"); + files_to_parse.insert("godot_ios/dummy.cpp"); files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata"); files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme"); - print_line("Unzipping..."); + IOSConfigData config_data = { + pkg_name, + binary_name, + _get_additional_plist_content(), + String(" ").join(_get_preset_architectures(p_preset)), + _get_linker_flags(), + _get_cpp_code() + }; + + DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir); + ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE) + print_line("Unzipping..."); + FileAccess *src_f = NULL; + zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); + if (!src_pkg_zip) { + EditorNode::add_io_error("Could not open export template (not a zip file?):\n" + src_pkg_name); + return ERR_CANT_OPEN; + } + ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN); + int ret = unzGoToFirstFile(src_pkg_zip); + Vector<uint8_t> project_file_data; while (ret == UNZ_OK) { bool is_execute = false; @@ -487,7 +793,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p //read unzOpenCurrentFile(src_pkg_zip); - unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size()); + unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size()); unzCloseCurrentFile(src_pkg_zip); //write @@ -496,15 +802,18 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p if (files_to_parse.has(file)) { print_line(String("parse ") + file); - _fix_config_file(p_preset, data, pkg_name, binary_name, p_debug); - } else if (file.begins_with("godot.iphone")) { - if (file != binary_to_use) { + _fix_config_file(p_preset, data, config_data, p_debug); + } else if (file.begins_with("libgodot.iphone")) { + if (file != library_to_use) { ret = unzGoToNextFile(src_pkg_zip); continue; //ignore! } - found_binary = true; + found_library = true; is_execute = true; - file = "godot_ios.iphone"; + file = "godot_ios.a"; + } + if (file == project_file) { + project_file_data = data; } ///@TODO need to parse logo files @@ -557,16 +866,16 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p /* we're done with our source zip */ unzClose(src_pkg_zip); - if (!found_binary) { - ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); + if (!found_library) { + ERR_PRINTS("Requested template library '" + library_to_use + "' not found. It might be missing from your template archive."); memdelete(tmp_app_path); return ERR_FILE_NOT_FOUND; } String iconset_dir = dest_dir + binary_name + "/Images.xcassets/AppIcon.appiconset/"; - Error err = OK; + err = OK; if (!tmp_app_path->dir_exists(iconset_dir)) { - Error err = tmp_app_path->make_dir_recursive(iconset_dir); + err = tmp_app_path->make_dir_recursive(iconset_dir); } memdelete(tmp_app_path); if (err) @@ -580,20 +889,23 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p if (err) return err; - ep.step("Making .pck", 1); - - String pack_path = dest_dir + binary_name + ".pck"; - err = save_pack(p_preset, pack_path); - if (err) - return err; - - err = export_project_files(p_preset, _export_dylibs, &dest_dir); - if (err) - return err; + print_line("Exporting additional assets"); + Vector<IOSExportAsset> assets; + _export_additional_assets(dest_dir + binary_name, libraries, assets); + _add_assets_to_project(project_file_data, assets); + String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj"; + FileAccess *f = FileAccess::open(project_file_name, FileAccess::WRITE); + if (!f) { + ERR_PRINTS("Can't write '" + project_file_name + "'."); + return ERR_CANT_CREATE; + }; + f->store_buffer(project_file_data.ptr(), project_file_data.size()); + f->close(); + memdelete(f); #ifdef OSX_ENABLED ep.step("Code-signing dylibs", 2); - DirAccess *dylibs_dir = DirAccess::open(dest_dir + "dylibs"); + DirAccess *dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs"); ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN); CodesignData codesign_data(p_preset, p_debug); err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); @@ -625,13 +937,14 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p export_args.push_back("-archivePath"); export_args.push_back(archive_path); export_args.push_back("-exportOptionsPlist"); - export_args.push_back(dest_dir + "export_options.plist"); + export_args.push_back(dest_dir + binary_name + "/export_options.plist"); + export_args.push_back("-allowProvisioningUpdates"); export_args.push_back("-exportPath"); export_args.push_back(dest_dir); err = OS::get_singleton()->execute("xcodebuild", export_args, true); ERR_FAIL_COND_V(err, err); #else - print_line(".ipa can only be built on macOS. Leaving XCode project without building the package."); + print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package."); #endif return OK; diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm index 531b80eee3..d2104ae765 100644 --- a/platform/iphone/game_center.mm +++ b/platform/iphone/game_center.mm @@ -109,7 +109,7 @@ void GameCenter::connect() { GameCenter::get_singleton()->authenticated = true; } else { ret["result"] = "error"; - ret["error_code"] = error.code; + ret["error_code"] = (int64_t)error.code; ret["error_description"] = [error.localizedDescription UTF8String]; GameCenter::get_singleton()->authenticated = false; }; @@ -145,7 +145,7 @@ Error GameCenter::post_score(Variant p_score) { ret["result"] = "ok"; } else { ret["result"] = "error"; - ret["error_code"] = error.code; + ret["error_code"] = (int64_t)error.code; ret["error_description"] = [error.localizedDescription UTF8String]; }; @@ -183,7 +183,7 @@ Error GameCenter::award_achievement(Variant p_params) { ret["result"] = "ok"; } else { ret["result"] = "error"; - ret["error_code"] = error.code; + ret["error_code"] = (int64_t)error.code; }; pending_events.push_back(ret); @@ -241,7 +241,7 @@ void GameCenter::request_achievement_descriptions() { } else { ret["result"] = "error"; - ret["error_code"] = error.code; + ret["error_code"] = (int64_t)error.code; }; pending_events.push_back(ret); @@ -273,7 +273,7 @@ void GameCenter::request_achievements() { } else { ret["result"] = "error"; - ret["error_code"] = error.code; + ret["error_code"] = (int64_t)error.code; }; pending_events.push_back(ret); @@ -289,7 +289,7 @@ void GameCenter::reset_achievements() { ret["result"] = "ok"; } else { ret["result"] = "error"; - ret["error_code"] = error.code; + ret["error_code"] = (int64_t)error.code; }; pending_events.push_back(ret); @@ -358,7 +358,7 @@ Error GameCenter::request_identity_verification_signature() { ret["player_id"] = [player.playerID UTF8String]; } else { ret["result"] = "error"; - ret["error_code"] = error.code; + ret["error_code"] = (int64_t)error.code; ret["error_description"] = [error.localizedDescription UTF8String]; }; diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index 95d7710c76..fbe3bd310d 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -46,6 +46,7 @@ #include "sem_iphone.h" #include "ios.h" +#include <dlfcn.h> int OSIPhone::get_video_driver_count() const { @@ -96,15 +97,6 @@ void OSIPhone::initialize_core() { set_data_dir(data_dir); }; -void OSIPhone::initialize_logger() { - Vector<Logger *> loggers; - loggers.push_back(memnew(SyslogLogger)); - // FIXME: Reenable once we figure out how to get this properly in user:// - // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) - //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); - _set_logger(memnew(CompositeLogger(loggers))); -} - void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { supported_orientations = 0; @@ -402,6 +394,37 @@ void OSIPhone::alert(const String &p_alert, const String &p_title) { iOS::alert(utf8_alert.get_data(), utf8_title.get_data()); } +Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handle) { + if (p_path.length() == 0) { + p_library_handle = RTLD_SELF; + return OK; + } + return OS_Unix::open_dynamic_library(p_path, p_library_handle); +} + +Error OSIPhone::close_dynamic_library(void *p_library_handle) { + if (p_library_handle == RTLD_SELF) { + return OK; + } + return OS_Unix::close_dynamic_library(p_library_handle); +} + +HashMap<String, void *> OSIPhone::dynamic_symbol_lookup_table; +void register_dynamic_symbol(char *name, void *address) { + OSIPhone::dynamic_symbol_lookup_table[String(name)] = address; +} + +Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { + if (p_library_handle == RTLD_SELF) { + void **ptr = OSIPhone::dynamic_symbol_lookup_table.getptr(p_name); + if (ptr) { + p_symbol_handle = *ptr; + return OK; + } + } + return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional); +} + void OSIPhone::set_video_mode(const VideoMode &p_video_mode, int p_screen) { video_mode = p_video_mode; @@ -558,7 +581,36 @@ bool OSIPhone::_check_internal_feature_support(const String &p_feature) { return p_feature == "mobile" || p_feature == "etc" || p_feature == "pvrtc" || p_feature == "etc2"; } +// Initialization order between compilation units is not guaranteed, +// so we use this as a hack to ensure certain code is called before +// everything else, but after all units are initialized. +typedef void (*init_callback)(); +static init_callback *ios_init_callbacks = NULL; +static int ios_init_callbacks_count = 0; +static int ios_init_callbacks_capacity = 0; + +void add_ios_init_callback(init_callback cb) { + if (ios_init_callbacks_count == ios_init_callbacks_capacity) { + void *new_ptr = realloc(ios_init_callbacks, sizeof(cb) * 32); + if (new_ptr) { + ios_init_callbacks = (init_callback *)(new_ptr); + ios_init_callbacks_capacity += 32; + } + } + if (ios_init_callbacks_capacity > ios_init_callbacks_count) { + ios_init_callbacks[ios_init_callbacks_count] = cb; + ++ios_init_callbacks_count; + } +} + OSIPhone::OSIPhone(int width, int height, String p_data_dir) { + for (int i = 0; i < ios_init_callbacks_count; ++i) { + ios_init_callbacks[i](); + } + free(ios_init_callbacks); + ios_init_callbacks = NULL; + ios_init_callbacks_count = 0; + ios_init_callbacks_capacity = 0; main_loop = NULL; visual_server = NULL; @@ -576,7 +628,13 @@ OSIPhone::OSIPhone(int width, int height, String p_data_dir) { // which is initialized in initialize_core data_dir = p_data_dir; - _set_logger(memnew(SyslogLogger)); + Vector<Logger *> loggers; + loggers.push_back(memnew(SyslogLogger)); +#ifdef DEBUG_ENABLED + // it seems iOS app's stdout/stderr is only obtainable if you launch it from Xcode + loggers.push_back(memnew(StdLogger)); +#endif + _set_logger(memnew(CompositeLogger(loggers))); }; OSIPhone::~OSIPhone() { diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 433228b599..1ef673765a 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -60,6 +60,9 @@ private: MAX_EVENTS = 64, }; + static HashMap<String, void *> dynamic_symbol_lookup_table; + friend void register_dynamic_symbol(char *name, void *address); + uint8_t supported_orientations; VisualServer *visual_server; @@ -83,7 +86,6 @@ private: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -153,6 +155,10 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle); + virtual Error close_dynamic_library(void *p_library_handle); + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); + virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0); virtual VideoMode get_video_mode(int p_screen = 0) const; virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const; diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 943f6d8f35..775e9c7ee0 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -155,6 +155,7 @@ String EditorExportPlatformJavaScript::get_binary_extension() const { } Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); String custom_debug = p_preset->get("custom_template/debug"); String custom_release = p_preset->get("custom_template/release"); @@ -213,7 +214,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese //read unzOpenCurrentFile(pkg); - unzReadCurrentFile(pkg, data.ptr(), data.size()); + unzReadCurrentFile(pkg, data.ptrw(), data.size()); unzCloseCurrentFile(pkg); //write @@ -256,7 +257,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese } Vector<uint8_t> buf; buf.resize(f->get_len()); - f->get_buffer(buf.ptr(), buf.size()); + f->get_buffer(buf.ptrw(), buf.size()); memdelete(f); _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug); diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 74cfec14a6..d5c675d9e0 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -80,10 +80,6 @@ void OS_JavaScript::initialize_core() { FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(FileAccess::ACCESS_RESOURCES); } -void OS_JavaScript::initialize_logger() { - _set_logger(memnew(StdLogger)); -} - void OS_JavaScript::set_opengl_extensions(const char *p_gl_extensions) { ERR_FAIL_COND(!p_gl_extensions); diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 77eeb02a9f..a95b069d03 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -81,7 +81,6 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; - virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index f6922377e3..8091a38adb 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -288,6 +288,7 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin } Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); String src_pkg_name; @@ -389,7 +390,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p //read unzOpenCurrentFile(src_pkg_zip); - unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size()); + unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size()); unzCloseCurrentFile(src_pkg_zip); //write diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index aa8ee1fe83..9a740a7bea 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -121,7 +121,6 @@ protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 110cb776ee..781e8de1ab 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -85,6 +85,15 @@ static int prev_mouse_y = 0; static int button_mask = 0; static bool mouse_down_control = false; +static Vector2 get_mouse_pos(NSEvent *event) { + + const NSRect contentRect = [OS_OSX::singleton->window_view frame]; + const NSPoint p = [event locationInWindow]; + mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); + mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); + return Vector2(mouse_x, mouse_y); +} + @interface GodotApplication : NSApplication @end @@ -508,12 +517,9 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { mm->set_button_mask(button_mask); prev_mouse_x = mouse_x; prev_mouse_y = mouse_y; - const NSRect contentRect = [OS_OSX::singleton->window_view frame]; - const NSPoint p = [event locationInWindow]; - mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); - mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); - mm->set_position(Vector2(mouse_x, mouse_y)); - mm->set_global_position(Vector2(mouse_x, mouse_y)); + const Vector2 pos = get_mouse_pos(event); + mm->set_position(pos); + mm->set_global_position(pos); Vector2 relativeMotion = Vector2(); relativeMotion.x = [event deltaX] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); relativeMotion.y = [event deltaY] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); @@ -575,6 +581,15 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { OS_OSX::singleton->input->set_mouse_in_window(true); } +- (void)magnifyWithEvent:(NSEvent *)event { + Ref<InputEventMagnifyGesture> ev; + ev.instance(); + get_key_modifier_state([event modifierFlags], ev); + ev->set_position(get_mouse_pos(event)); + ev->set_factor([event magnification] + 1.0); + OS_OSX::singleton->push_input(ev); +} + - (void)viewDidChangeBackingProperties { // nothing left to do here } @@ -838,6 +853,18 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) { OS_OSX::singleton->push_input(sc); } +inline void sendPanEvent(double dx, double dy, int modifierFlags) { + + Ref<InputEventPanGesture> pg; + pg.instance(); + + get_key_modifier_state(modifierFlags, pg); + Vector2 mouse_pos = Vector2(mouse_x, mouse_y); + pg->set_position(mouse_pos); + pg->set_delta(Vector2(-dx, -dy)); + OS_OSX::singleton->push_input(pg); +} + - (void)scrollWheel:(NSEvent *)event { double deltaX, deltaY; @@ -856,11 +883,16 @@ inline void sendScrollEvent(int button, double factor, int modifierFlags) { deltaX = [event deltaX]; deltaY = [event deltaY]; } - if (fabs(deltaX)) { - sendScrollEvent(0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]); - } - if (fabs(deltaY)) { - sendScrollEvent(0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]); + + if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) { + sendPanEvent(deltaX, deltaY, [event modifierFlags]); + } else { + if (fabs(deltaX)) { + sendScrollEvent(0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]); + } + if (fabs(deltaY)) { + sendScrollEvent(0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]); + } } } @@ -1185,15 +1217,6 @@ public: typedef UnixTerminalLogger OSXTerminalLogger; #endif -void OS_OSX::initialize_logger() { - Vector<Logger *> loggers; - loggers.push_back(memnew(OSXTerminalLogger)); - // FIXME: Reenable once we figure out how to get this properly in user:// - // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) - //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); - _set_logger(memnew(CompositeLogger(loggers))); -} - void OS_OSX::alert(const String &p_alert, const String &p_title) { // Set OS X-compliant variables NSAlert *window = [[NSAlert alloc] init]; @@ -2142,7 +2165,9 @@ OS_OSX::OS_OSX() { window_size = Vector2(1024, 600); zoomed = false; - _set_logger(memnew(OSXTerminalLogger)); + Vector<Logger *> loggers; + loggers.push_back(memnew(OSXTerminalLogger)); + _set_logger(memnew(CompositeLogger(loggers))); } bool OS_OSX::_check_internal_feature_support(const String &p_feature) { diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 120df9bc3f..7f86b4ae53 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -137,7 +137,7 @@ class AppxPackager { ZPOS64_T end_of_central_dir_offset; Vector<uint8_t> central_dir_data; - String hash_block(uint8_t *p_block_data, size_t p_block_len); + String hash_block(const uint8_t *p_block_data, size_t p_block_len); void make_block_map(); void make_content_types(); @@ -188,14 +188,14 @@ public: /////////////////////////////////////////////////////////////////////////// -String AppxPackager::hash_block(uint8_t *p_block_data, size_t p_block_len) { +String AppxPackager::hash_block(const uint8_t *p_block_data, size_t p_block_len) { char hash[32]; char base64[45]; sha256_context ctx; sha256_init(&ctx); - sha256_hash(&ctx, p_block_data, p_block_len); + sha256_hash(&ctx, (uint8_t *)p_block_data, p_block_len); sha256_done(&ctx, (uint8_t *)hash); base64_encode(base64, hash, 32); @@ -510,8 +510,8 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t strm.avail_in = block_size; strm.avail_out = strm_out.size(); - strm.next_in = strm_in.ptr(); - strm.next_out = strm_out.ptr(); + strm.next_in = (uint8_t *)strm_in.ptr(); + strm.next_out = strm_out.ptrw(); int total_out_before = strm.total_out; @@ -541,8 +541,8 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t strm.avail_in = 0; strm.avail_out = strm_out.size(); - strm.next_in = strm_in.ptr(); - strm.next_out = strm_out.ptr(); + strm.next_in = (uint8_t *)strm_in.ptr(); + strm.next_out = strm_out.ptrw(); int total_out_before = strm.total_out; @@ -588,7 +588,7 @@ void AppxPackager::finish() { Vector<uint8_t> blockmap_buffer; blockmap_buffer.resize(blockmap_file->get_len()); - blockmap_file->get_buffer(blockmap_buffer.ptr(), blockmap_buffer.size()); + blockmap_file->get_buffer(blockmap_buffer.ptrw(), blockmap_buffer.size()); add_file("AppxBlockMap.xml", blockmap_buffer.ptr(), blockmap_buffer.size(), -1, -1, true); @@ -604,7 +604,7 @@ void AppxPackager::finish() { Vector<uint8_t> types_buffer; types_buffer.resize(types_file->get_len()); - types_file->get_buffer(types_buffer.ptr(), types_buffer.size()); + types_file->get_buffer(types_buffer.ptrw(), types_buffer.size()); add_file("[Content_Types].xml", types_buffer.ptr(), types_buffer.size(), -1, -1, true); @@ -911,7 +911,7 @@ class EditorExportUWP : public EditorExportPlatform { } data.resize(f->get_len()); - f->get_buffer(data.ptr(), data.size()); + f->get_buffer(data.ptrw(), data.size()); f->close(); memdelete(f); @@ -1301,7 +1301,7 @@ public: if (do_read) { data.resize(info.uncompressed_size); unzOpenCurrentFile(pkg); - unzReadCurrentFile(pkg, data.ptr(), data.size()); + unzReadCurrentFile(pkg, data.ptrw(), data.size()); unzCloseCurrentFile(pkg); } @@ -1341,7 +1341,7 @@ public: // Argc clf.resize(4); - encode_uint32(cl.size(), clf.ptr()); + encode_uint32(cl.size(), clf.ptrw()); for (int i = 0; i < cl.size(); i++) { diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 64e319327f..1655caf04b 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -179,15 +179,6 @@ void OSUWP::initialize_core() { cursor_shape = CURSOR_ARROW; } -void OSUWP::initialize_logger() { - Vector<Logger *> loggers; - loggers.push_back(memnew(WindowsTerminalLogger)); - // FIXME: Reenable once we figure out how to get this properly in user:// - // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) - //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); - _set_logger(memnew(CompositeLogger(loggers))); -} - bool OSUWP::can_draw() const { return !minimized; @@ -834,7 +825,9 @@ OSUWP::OSUWP() { AudioDriverManager::add_driver(&audio_driver); - _set_logger(memnew(WindowsTerminalLogger)); + Vector<Logger *> loggers; + loggers.push_back(memnew(WindowsTerminalLogger)); + _set_logger(memnew(CompositeLogger(loggers))); } OSUWP::~OSUWP() { diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 3c52fc29a8..8d69cd53fd 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -157,7 +157,6 @@ protected: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; - virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 72d51ad62a..827189bb4f 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -201,15 +201,6 @@ void OS_Windows::initialize_core() { cursor_shape = CURSOR_ARROW; } -void OS_Windows::initialize_logger() { - Vector<Logger *> loggers; - loggers.push_back(memnew(WindowsTerminalLogger)); - // FIXME: Reenable once we figure out how to get this properly in user:// - // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) - //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); - _set_logger(memnew(CompositeLogger(loggers))); -} - bool OS_Windows::can_draw() const { return !minimized; @@ -1852,7 +1843,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, modstr.resize(cmdline.size()); for (int i = 0; i < cmdline.size(); i++) modstr[i] = cmdline[i]; - int ret = CreateProcessW(NULL, modstr.ptr(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, si_w, &pi.pi); + int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, si_w, &pi.pi); ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK); if (p_blocking) { @@ -2326,7 +2317,9 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { AudioDriverManager::add_driver(&driver_xaudio2); #endif - _set_logger(memnew(WindowsTerminalLogger)); + Vector<Logger *> loggers; + loggers.push_back(memnew(WindowsTerminalLogger)); + _set_logger(memnew(CompositeLogger(loggers))); } OS_Windows::~OS_Windows() { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 5e0c240dba..4367297262 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -145,7 +145,6 @@ protected: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; - virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index c1d744215d..d1aa129e77 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -250,41 +250,13 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); } - - // borderless fullscreen window mode - if (current_videomode.fullscreen) { - // set bypass compositor hint - Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False); - unsigned long compositing_disable_on = 1; - XChangeProperty(x11_display, x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1); - - // needed for lxde/openbox, possibly others - Hints hints; - Atom property; - hints.flags = 2; - hints.decorations = 0; - property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); - XMapRaised(x11_display, x11_window); - XWindowAttributes xwa; - XGetWindowAttributes(x11_display, DefaultRootWindow(x11_display), &xwa); - XMoveResizeWindow(x11_display, x11_window, 0, 0, xwa.width, xwa.height); - - // code for netwm-compliants - XEvent xev; - Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); - Atom fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False); - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = x11_window; - xev.xclient.message_type = wm_state; - xev.xclient.format = 32; - xev.xclient.data.l[0] = 1; - xev.xclient.data.l[1] = fullscreen; - xev.xclient.data.l[2] = 0; - - XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureNotifyMask, &xev); + if (current_videomode.maximized) { + current_videomode.maximized = false; + set_window_maximized(true); + // borderless fullscreen window mode + } else if (current_videomode.fullscreen) { + current_videomode.fullscreen = false; + set_window_fullscreen(true); } else if (current_videomode.borderless_window) { Hints hints; Atom property; @@ -467,8 +439,17 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au _ensure_user_data_dir(); power_manager = memnew(PowerX11); + + XEvent xevent; + while (XCheckIfEvent(x11_display, &xevent, _check_window_events, NULL)) { + _window_changed(&xevent); + } } +int OS_X11::_check_window_events(Display *display, XEvent *event, char *arg) { + if (event->type == ConfigureNotify) return 1; + return 0; +} void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data, ::XPointer call_data) { @@ -648,6 +629,9 @@ void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) con } void OS_X11::set_wm_fullscreen(bool p_enabled) { + if (current_videomode.fullscreen == p_enabled) + return; + if (p_enabled && !is_window_resizable()) { // Set the window as resizable to prevent window managers to ignore the fullscreen state flag. XSizeHints *xsh; @@ -971,6 +955,9 @@ bool OS_X11::is_window_minimized() const { } void OS_X11::set_window_maximized(bool p_enabled) { + if (is_window_maximized() == p_enabled) + return; + // Using EWMH -- Extended Window Manager Hints XEvent xev; Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); @@ -1417,6 +1404,20 @@ static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p return None; } +void OS_X11::_window_changed(XEvent *event) { + + if (xic) { + // Not portable. + set_ime_position(Point2(0, 1)); + } + if ((event->xconfigure.width == current_videomode.width) && + (event->xconfigure.height == current_videomode.height)) + return; + + current_videomode.width = event->xconfigure.width; + current_videomode.height = event->xconfigure.height; +} + void OS_X11::process_xevents() { //printf("checking events %i\n", XPending(x11_display)); @@ -1498,18 +1499,7 @@ void OS_X11::process_xevents() { break; case ConfigureNotify: - if (xic) { - // Not portable. - set_ime_position(Point2(0, 1)); - } - /* call resizeGLScene only if our window-size changed */ - - if ((event.xconfigure.width == current_videomode.width) && - (event.xconfigure.height == current_videomode.height)) - break; - - current_videomode.width = event.xconfigure.width; - current_videomode.height = event.xconfigure.height; + _window_changed(&event); break; case ButtonPress: case ButtonRelease: { diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 67f3807d99..a74e6ee5f3 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -187,6 +187,9 @@ protected: virtual void set_main_loop(MainLoop *p_main_loop); + void _window_changed(XEvent *xevent); + static int _check_window_events(Display *display, XEvent *xevent, char *arg); + public: virtual String get_name(); |