diff options
Diffstat (limited to 'platform')
181 files changed, 3996 insertions, 1806 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub index ad226255bc..d370a4d18d 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -6,6 +6,7 @@ android_files = [ "os_android.cpp", "android_input_handler.cpp", "file_access_android.cpp", + "file_access_filesystem_jandroid.cpp", "audio_driver_opensl.cpp", "dir_access_jandroid.cpp", "tts_android.cpp", diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp index 10f23b320b..81802298d9 100644 --- a/platform/android/android_input_handler.cpp +++ b/platform/android/android_input_handler.cpp @@ -381,13 +381,3 @@ MouseButton AndroidInputHandler::_android_button_mask_to_godot_button_mask(int a return godot_button_mask; } - -void AndroidInputHandler::process_scroll(Point2 p_pos) { - Ref<InputEventPanGesture> ev; - ev.instantiate(); - _set_key_modifier_state(ev); - ev->set_position(p_pos); - ev->set_delta(p_pos - scroll_prev_pos); - Input::get_singleton()->parse_input_event(ev); - scroll_prev_pos = p_pos; -} diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h index e9c0ec1475..1397ca59e4 100644 --- a/platform/android/android_input_handler.h +++ b/platform/android/android_input_handler.h @@ -69,7 +69,6 @@ private: Vector<TouchPos> touch; Point2 hover_prev_pos; // needed to calculate the relative position on hover events - Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events void _set_key_modifier_state(Ref<InputEventWithModifiers> ev); @@ -83,7 +82,6 @@ public: void process_hover(int p_type, Point2 p_pos); void process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0); void process_double_tap(int event_android_button_mask, Point2 p_pos); - void process_scroll(Point2 p_pos); void process_joy_event(JoypadEvent p_event); void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); }; diff --git a/platform/android/detect.py b/platform/android/detect.py index 0099ac7e0d..2ff5bf59ea 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -1,7 +1,7 @@ import os import sys import platform -from distutils.version import LooseVersion +import subprocess def is_active(): @@ -13,41 +13,35 @@ def get_name(): def can_build(): - return ("ANDROID_SDK_ROOT" in os.environ) or ("ANDROID_HOME" in os.environ) - - -def get_platform(platform): - return int(platform.split("-")[1]) + return os.path.exists(get_env_android_sdk_root()) def get_opts(): from SCons.Variables import BoolVariable, EnumVariable return [ - ("ANDROID_NDK_ROOT", "Path to the Android NDK", get_android_ndk_root()), - ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_android_sdk_root()), + ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_env_android_sdk_root()), ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"), EnumVariable("android_arch", "Target architecture", "arm64v8", ("armv7", "arm64v8", "x86", "x86_64")), ] # Return the ANDROID_SDK_ROOT environment variable. -# While ANDROID_HOME has been deprecated, it's used as a fallback for backward -# compatibility purposes. -def get_android_sdk_root(): - if "ANDROID_SDK_ROOT" in os.environ: - return os.environ.get("ANDROID_SDK_ROOT", 0) - else: - return os.environ.get("ANDROID_HOME", 0) +def get_env_android_sdk_root(): + return os.environ.get("ANDROID_SDK_ROOT", -1) -# Return the ANDROID_NDK_ROOT environment variable. -# We generate one for this build using the ANDROID_SDK_ROOT env -# variable and the project ndk version. -# If the env variable is already defined, we override it with -# our own to match what the project expects. -def get_android_ndk_root(): - return get_android_sdk_root() + "/ndk/" + get_project_ndk_version() +def get_min_sdk_version(platform): + return int(platform.split("-")[1]) + + +def get_android_ndk_root(env): + return env["ANDROID_SDK_ROOT"] + "/ndk/" + get_ndk_version() + + +# This is kept in sync with the value in 'platform/android/java/app/config.gradle'. +def get_ndk_version(): + return "23.2.8568313" def get_flags(): @@ -56,133 +50,67 @@ def get_flags(): ] -def create(env): - tools = env["TOOLS"] - if "mingw" in tools: - tools.remove("mingw") - if "applelink" in tools: - tools.remove("applelink") - env.Tool("gcc") - return env.Clone(tools=tools) - - -# Check if ANDROID_NDK_ROOT is valid. -# If not, install the ndk using ANDROID_SDK_ROOT and sdkmanager. +# Check if Android NDK version is installed +# If not, install it. def install_ndk_if_needed(env): print("Checking for Android NDK...") - env_ndk_version = get_env_ndk_version(env["ANDROID_NDK_ROOT"]) - if env_ndk_version is None: - # Reinstall the ndk and update ANDROID_NDK_ROOT. - print("Installing Android NDK...") - if env["ANDROID_SDK_ROOT"] is None: - raise Exception("Invalid ANDROID_SDK_ROOT environment variable.") - - import subprocess - + sdk_root = env["ANDROID_SDK_ROOT"] + if not os.path.exists(get_android_ndk_root(env)): extension = ".bat" if os.name == "nt" else "" - sdkmanager_path = env["ANDROID_SDK_ROOT"] + "/cmdline-tools/latest/bin/sdkmanager" + extension - ndk_download_args = "ndk;" + get_project_ndk_version() - subprocess.check_call([sdkmanager_path, ndk_download_args]) - - env["ANDROID_NDK_ROOT"] = env["ANDROID_SDK_ROOT"] + "/ndk/" + get_project_ndk_version() - print("ANDROID_NDK_ROOT: " + env["ANDROID_NDK_ROOT"]) + sdkmanager = sdk_root + "/cmdline-tools/latest/bin/sdkmanager" + extension + if os.path.exists(sdkmanager): + # Install the Android NDK + print("Installing Android NDK...") + ndk_download_args = "ndk;" + get_ndk_version() + subprocess.check_call([sdkmanager, ndk_download_args]) + else: + print("Cannot find " + sdkmanager) + print( + "Please ensure ANDROID_SDK_ROOT is correct and cmdline-tools are installed, or install NDK version " + + get_ndk_version() + + " manually." + ) + sys.exit() + env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env) def configure(env): install_ndk_if_needed(env) - - # Workaround for MinGW. See: - # https://www.scons.org/wiki/LongCmdLinesOnWin32 - if os.name == "nt": - - import subprocess - - def mySubProcess(cmdline, env): - # print("SPAWNED : " + cmdline) - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - proc = subprocess.Popen( - cmdline, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - startupinfo=startupinfo, - shell=False, - env=env, - ) - data, err = proc.communicate() - rv = proc.wait() - if rv: - print("=====") - print(err) - print("=====") - return rv - - def mySpawn(sh, escape, cmd, args, env): - - newargs = " ".join(args[1:]) - cmdline = cmd + " " + newargs - - rv = 0 - if len(cmdline) > 32000 and cmd.endswith("ar"): - cmdline = cmd + " " + args[1] + " " + args[2] + " " - for i in range(3, len(args)): - rv = mySubProcess(cmdline + args[i], env) - if rv: - break - else: - rv = mySubProcess(cmdline, env) - - return rv - - env["SPAWN"] = mySpawn + ndk_root = env["ANDROID_NDK_ROOT"] # Architecture if env["android_arch"] not in ["armv7", "arm64v8", "x86", "x86_64"]: - env["android_arch"] = "armv7" + env["android_arch"] = "arm64v8" print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")") - can_vectorize = True - if env["android_arch"] == "x86": - env["ARCH"] = "arch-x86" - env.extra_suffix = ".x86" + env.extra_suffix - target_subpath = "x86-4.9" - abi_subpath = "i686-linux-android" - arch_subpath = "x86" - env["x86_libtheora_opt_gcc"] = True - elif env["android_arch"] == "x86_64": - if get_platform(env["ndk_platform"]) < 21: + if get_min_sdk_version(env["ndk_platform"]) < 21: + if env["android_arch"] == "x86_64" or env["android_arch"] == "arm64v8": print( - "WARNING: android_arch=x86_64 is not supported by ndk_platform lower than android-21; setting" - " ndk_platform=android-21" + "WARNING: android_arch=" + + env["android_arch"] + + " is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21" ) env["ndk_platform"] = "android-21" - env["ARCH"] = "arch-x86_64" - env.extra_suffix = ".x86_64" + env.extra_suffix - target_subpath = "x86_64-4.9" - abi_subpath = "x86_64-linux-android" - arch_subpath = "x86_64" - env["x86_libtheora_opt_gcc"] = True - elif env["android_arch"] == "armv7": - env["ARCH"] = "arch-arm" - target_subpath = "arm-linux-androideabi-4.9" - abi_subpath = "arm-linux-androideabi" - arch_subpath = "armeabi-v7a" + + if env["android_arch"] == "armv7": + target_triple = "armv7a-linux-androideabi" env.extra_suffix = ".armv7" + env.extra_suffix elif env["android_arch"] == "arm64v8": - if get_platform(env["ndk_platform"]) < 21: - print( - "WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than android-21; setting" - " ndk_platform=android-21" - ) - env["ndk_platform"] = "android-21" - env["ARCH"] = "arch-arm64" - target_subpath = "aarch64-linux-android-4.9" - abi_subpath = "aarch64-linux-android" - arch_subpath = "arm64-v8a" + target_triple = "aarch64-linux-android" env.extra_suffix = ".armv8" + env.extra_suffix + elif env["android_arch"] == "x86": + target_triple = "i686-linux-android" + env.extra_suffix = ".x86" + env.extra_suffix + elif env["android_arch"] == "x86_64": + target_triple = "x86_64-linux-android" + env.extra_suffix = ".x86_64" + env.extra_suffix + + target_option = ["-target", target_triple + str(get_min_sdk_version(env["ndk_platform"]))] + env.Append(ASFLAGS=[target_option, "-c"]) + env.Append(CCFLAGS=target_option) + env.Append(LINKFLAGS=target_option) # Build type @@ -191,15 +119,11 @@ def configure(env): # `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces # when using `target=release_debug`. opt = "-O3" if env["target"] == "release" else "-O2" - env.Append(LINKFLAGS=[opt]) env.Append(CCFLAGS=[opt, "-fomit-frame-pointer"]) elif env["optimize"] == "size": # optimize for size - env.Append(CCFLAGS=["-Os"]) - env.Append(LINKFLAGS=["-Os"]) - + env.Append(CCFLAGS=["-Oz"]) env.Append(CPPDEFINES=["NDEBUG"]) - if can_vectorize: - env.Append(CCFLAGS=["-ftree-vectorize"]) + env.Append(CCFLAGS=["-ftree-vectorize"]) elif env["target"] == "debug": env.Append(LINKFLAGS=["-O0"]) env.Append(CCFLAGS=["-O0", "-g", "-fno-limit-debug-info"]) @@ -211,7 +135,6 @@ def configure(env): env["SHLIBSUFFIX"] = ".so" if env["PLATFORM"] == "win32": - env.Tool("gcc") env.use_windows_spawn_fix() if sys.platform.startswith("linux"): @@ -224,32 +147,14 @@ def configure(env): else: host_subpath = "windows" - compiler_path = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin" - gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath - tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin" - - # For Clang to find NDK tools in preference of those system-wide - env.PrependENVPath("PATH", tools_path) - - ccache_path = os.environ.get("CCACHE") - if ccache_path is None: - env["CC"] = compiler_path + "/clang" - env["CXX"] = compiler_path + "/clang++" - else: - # there aren't any ccache wrappers available for Android, - # to enable caching we need to prepend the path to the ccache binary - env["CC"] = ccache_path + " " + compiler_path + "/clang" - env["CXX"] = ccache_path + " " + compiler_path + "/clang++" - env["AR"] = tools_path + "/ar" - env["RANLIB"] = tools_path + "/ranlib" - env["AS"] = tools_path + "/as" + toolchain_path = ndk_root + "/toolchains/llvm/prebuilt/" + host_subpath + compiler_path = toolchain_path + "/bin" - common_opts = ["-gcc-toolchain", gcc_toolchain_path] - - # Compile flags - - env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/include"]) - env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"]) + env["CC"] = compiler_path + "/clang" + env["CXX"] = compiler_path + "/clang++" + env["AR"] = compiler_path + "/llvm-ar" + env["RANLIB"] = compiler_path + "/llvm-ranlib" + env["AS"] = compiler_path + "/clang" # Disable exceptions and rtti on non-tools (template) builds if env["tools"]: @@ -261,100 +166,31 @@ def configure(env): # Don't use dynamic_cast, necessary with no-rtti. env.Append(CPPDEFINES=["NO_SAFE_CAST"]) - lib_sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env["ndk_platform"] + "/" + env["ARCH"] - - # Using NDK unified headers (NDK r15+) - sysroot = env["ANDROID_NDK_ROOT"] + "/sysroot" - env.Append(CPPFLAGS=["--sysroot=" + sysroot]) - env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include/" + abi_subpath]) - env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/android/support/include"]) - # For unified headers this define has to be set manually - env.Append(CPPDEFINES=[("__ANDROID_API__", str(get_platform(env["ndk_platform"])))]) - env.Append( CCFLAGS=( - "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden" - " -fno-strict-aliasing".split() + "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split() ) ) env.Append(CPPDEFINES=["NO_STATVFS", "GLES_ENABLED"]) - if get_platform(env["ndk_platform"]) >= 24: + if get_min_sdk_version(env["ndk_platform"]) >= 24: env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) if env["android_arch"] == "x86": - target_opts = ["-target", "i686-none-linux-android"] - # The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least + # The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least env.Append(CCFLAGS=["-mstackrealign"]) - - elif env["android_arch"] == "x86_64": - target_opts = ["-target", "x86_64-none-linux-android"] - elif env["android_arch"] == "armv7": - target_opts = ["-target", "armv7-none-linux-androideabi"] env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split()) env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"]) - # Enable ARM NEON instructions to compile more optimized code. - env.Append(CCFLAGS=["-mfpu=neon"]) env.Append(CPPDEFINES=["__ARM_NEON__"]) - elif env["android_arch"] == "arm64v8": - target_opts = ["-target", "aarch64-none-linux-android"] env.Append(CCFLAGS=["-mfix-cortex-a53-835769"]) env.Append(CPPDEFINES=["__ARM_ARCH_8A__"]) - env.Append(CCFLAGS=target_opts) - env.Append(CCFLAGS=common_opts) - # Link flags - ndk_version = get_env_ndk_version(env["ANDROID_NDK_ROOT"]) - if ndk_version != None and LooseVersion(ndk_version) >= LooseVersion("17.1.4828580"): - env.Append(LINKFLAGS=["-Wl,--exclude-libs,libgcc.a", "-Wl,--exclude-libs,libatomic.a", "-nostdlib++"]) - else: - env.Append( - LINKFLAGS=[ - env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libandroid_support.a" - ] - ) - env.Append(LINKFLAGS=["-shared", "--sysroot=" + lib_sysroot, "-Wl,--warn-shared-textrel"]) - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/"]) - env.Append( - LINKFLAGS=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libc++_shared.so"] - ) - - if env["android_arch"] == "armv7": - env.Append(LINKFLAGS="-Wl,--fix-cortex-a8".split()) - env.Append(LINKFLAGS="-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now".split()) - env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so -Wl,--gc-sections".split()) - - env.Append(LINKFLAGS=target_opts) - env.Append(LINKFLAGS=common_opts) - - env.Append( - LIBPATH=[ - env["ANDROID_NDK_ROOT"] - + "/toolchains/" - + target_subpath - + "/prebuilt/" - + host_subpath - + "/lib/gcc/" - + abi_subpath - + "/4.9.x" - ] - ) - env.Append( - LIBPATH=[ - env["ANDROID_NDK_ROOT"] - + "/toolchains/" - + target_subpath - + "/prebuilt/" - + host_subpath - + "/" - + abi_subpath - + "/lib" - ] - ) + env.Append(LINKFLAGS="-Wl,--gc-sections -Wl,--no-undefined -Wl,-z,now".split()) + env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so") env.Prepend(CPPPATH=["#platform/android"]) env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED", "NO_FCNTL"]) @@ -364,25 +200,3 @@ def configure(env): env.Append(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: env.Append(LIBS=["vulkan"]) - - -# Return the project NDK version. -# This is kept in sync with the value in 'platform/android/java/app/config.gradle'. -def get_project_ndk_version(): - return "21.4.7075529" - - -# Return NDK version string in source.properties (adapted from the Chromium project). -def get_env_ndk_version(path): - if path is None: - return None - prop_file_path = os.path.join(path, "source.properties") - try: - with open(prop_file_path) as prop_file: - for line in prop_file: - key_value = list(map(lambda x: x.strip(), line.split("="))) - if key_value[0] == "Pkg.Revision": - return key_value[1] - except Exception: - print("Could not read source prop file '%s'" % prop_file_path) - return None diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 5b9eee8117..eb344d3b43 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -31,30 +31,32 @@ #include "dir_access_jandroid.h" #include "core/string/print_string.h" -#include "file_access_android.h" #include "string_android.h" #include "thread_jandroid.h" -jobject DirAccessJAndroid::io = nullptr; +jobject DirAccessJAndroid::dir_access_handler = nullptr; jclass DirAccessJAndroid::cls = nullptr; jmethodID DirAccessJAndroid::_dir_open = nullptr; jmethodID DirAccessJAndroid::_dir_next = nullptr; jmethodID DirAccessJAndroid::_dir_close = nullptr; jmethodID DirAccessJAndroid::_dir_is_dir = nullptr; - -Ref<DirAccess> DirAccessJAndroid::create_fs() { - return memnew(DirAccessJAndroid); -} +jmethodID DirAccessJAndroid::_dir_exists = nullptr; +jmethodID DirAccessJAndroid::_file_exists = nullptr; +jmethodID DirAccessJAndroid::_get_drive_count = nullptr; +jmethodID DirAccessJAndroid::_get_drive = nullptr; +jmethodID DirAccessJAndroid::_make_dir = nullptr; +jmethodID DirAccessJAndroid::_get_space_left = nullptr; +jmethodID DirAccessJAndroid::_rename = nullptr; +jmethodID DirAccessJAndroid::_remove = nullptr; +jmethodID DirAccessJAndroid::_current_is_hidden = nullptr; Error DirAccessJAndroid::list_dir_begin() { list_dir_end(); - JNIEnv *env = get_jni_env(); - - jstring js = env->NewStringUTF(current_dir.utf8().get_data()); - int res = env->CallIntMethod(io, _dir_open, js); + int res = dir_open(current_dir); if (res <= 0) { return ERR_CANT_OPEN; } + id = res; return OK; @@ -62,169 +64,236 @@ Error DirAccessJAndroid::list_dir_begin() { String DirAccessJAndroid::get_next() { ERR_FAIL_COND_V(id == 0, ""); + if (_dir_next) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, ""); + jstring str = (jstring)env->CallObjectMethod(dir_access_handler, _dir_next, get_access_type(), id); + if (!str) { + return ""; + } - JNIEnv *env = get_jni_env(); - jstring str = (jstring)env->CallObjectMethod(io, _dir_next, id); - if (!str) { + String ret = jstring_to_string((jstring)str, env); + env->DeleteLocalRef((jobject)str); + return ret; + } else { return ""; } - String ret = jstring_to_string((jstring)str, env); - env->DeleteLocalRef((jobject)str); - return ret; } bool DirAccessJAndroid::current_is_dir() const { - JNIEnv *env = get_jni_env(); - - return env->CallBooleanMethod(io, _dir_is_dir, id); + if (_dir_is_dir) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, false); + return env->CallBooleanMethod(dir_access_handler, _dir_is_dir, get_access_type(), id); + } else { + return false; + } } bool DirAccessJAndroid::current_is_hidden() const { - return current != "." && current != ".." && current.begins_with("."); + if (_current_is_hidden) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, false); + return env->CallBooleanMethod(dir_access_handler, _current_is_hidden, get_access_type(), id); + } + return false; } void DirAccessJAndroid::list_dir_end() { if (id == 0) { return; } - JNIEnv *env = get_jni_env(); - env->CallVoidMethod(io, _dir_close, id); + + dir_close(id); id = 0; } int DirAccessJAndroid::get_drive_count() { - return 0; + if (_get_drive_count) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, 0); + return env->CallIntMethod(dir_access_handler, _get_drive_count, get_access_type()); + } else { + return 0; + } } String DirAccessJAndroid::get_drive(int p_drive) { - return ""; + if (_get_drive) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, ""); + jstring j_drive = (jstring)env->CallObjectMethod(dir_access_handler, _get_drive, get_access_type(), p_drive); + if (!j_drive) { + return ""; + } + + String drive = jstring_to_string(j_drive, env); + env->DeleteLocalRef(j_drive); + return drive; + } else { + return ""; + } } Error DirAccessJAndroid::change_dir(String p_dir) { - JNIEnv *env = get_jni_env(); - - if (p_dir.is_empty() || p_dir == "." || (p_dir == ".." && current_dir.is_empty())) { + String new_dir = get_absolute_path(p_dir); + if (new_dir == current_dir) { return OK; } - String new_dir; - - if (p_dir != "res://" && p_dir.length() > 1 && p_dir.ends_with("/")) { - p_dir = p_dir.substr(0, p_dir.length() - 1); - } - - if (p_dir.begins_with("/")) { - new_dir = p_dir.substr(1, p_dir.length()); - } else if (p_dir.begins_with("res://")) { - new_dir = p_dir.substr(6, p_dir.length()); - } else if (current_dir.is_empty()) { - new_dir = p_dir; - } else { - new_dir = current_dir.plus_file(p_dir); - } - - //test if newdir exists - new_dir = new_dir.simplify_path(); - - jstring js = env->NewStringUTF(new_dir.utf8().get_data()); - int res = env->CallIntMethod(io, _dir_open, js); - env->DeleteLocalRef(js); - if (res <= 0) { + if (!dir_exists(new_dir)) { return ERR_INVALID_PARAMETER; } - env->CallVoidMethod(io, _dir_close, res); - current_dir = new_dir; - return OK; } -String DirAccessJAndroid::get_current_dir(bool p_include_drive) const { - return "res://" + current_dir; +String DirAccessJAndroid::get_absolute_path(String p_path) { + if (current_dir != "" && p_path == current_dir) { + return current_dir; + } + + if (p_path.is_relative_path()) { + p_path = get_current_dir().plus_file(p_path); + } + + p_path = fix_path(p_path); + p_path = p_path.simplify_path(); + return p_path; } bool DirAccessJAndroid::file_exists(String p_file) { - String sd; - if (current_dir.is_empty()) { - sd = p_file; + if (_file_exists) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, false); + + String path = get_absolute_path(p_file); + jstring j_path = env->NewStringUTF(path.utf8().get_data()); + bool result = env->CallBooleanMethod(dir_access_handler, _file_exists, get_access_type(), j_path); + env->DeleteLocalRef(j_path); + return result; } else { - sd = current_dir.plus_file(p_file); + return false; } - - Ref<FileAccessAndroid> f; - f.instantiate(); - bool exists = f->file_exists(sd); - - return exists; } bool DirAccessJAndroid::dir_exists(String p_dir) { - JNIEnv *env = get_jni_env(); - - String sd; - - if (current_dir.is_empty()) { - sd = p_dir; + if (_dir_exists) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, false); + + String path = get_absolute_path(p_dir); + jstring j_path = env->NewStringUTF(path.utf8().get_data()); + bool result = env->CallBooleanMethod(dir_access_handler, _dir_exists, get_access_type(), j_path); + env->DeleteLocalRef(j_path); + return result; } else { - if (p_dir.is_relative_path()) { - sd = current_dir.plus_file(p_dir); - } else { - sd = fix_path(p_dir); - } - } - - String path = sd.simplify_path(); - - if (path.begins_with("/")) { - path = path.substr(1, path.length()); - } else if (path.begins_with("res://")) { - path = path.substr(6, path.length()); + return false; } +} - jstring js = env->NewStringUTF(path.utf8().get_data()); - int res = env->CallIntMethod(io, _dir_open, js); - env->DeleteLocalRef(js); - if (res <= 0) { - return false; +Error DirAccessJAndroid::make_dir_recursive(String p_dir) { + // Check if the directory exists already + if (dir_exists(p_dir)) { + return ERR_ALREADY_EXISTS; } - env->CallVoidMethod(io, _dir_close, res); + if (_make_dir) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, ERR_UNCONFIGURED); - return true; + String path = get_absolute_path(p_dir); + jstring j_dir = env->NewStringUTF(path.utf8().get_data()); + bool result = env->CallBooleanMethod(dir_access_handler, _make_dir, get_access_type(), j_dir); + env->DeleteLocalRef(j_dir); + if (result) { + return OK; + } else { + return FAILED; + } + } else { + return ERR_UNCONFIGURED; + } } Error DirAccessJAndroid::make_dir(String p_dir) { - ERR_FAIL_V(ERR_UNAVAILABLE); + return make_dir_recursive(p_dir); } Error DirAccessJAndroid::rename(String p_from, String p_to) { - ERR_FAIL_V(ERR_UNAVAILABLE); -} + if (_rename) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, ERR_UNCONFIGURED); -Error DirAccessJAndroid::remove(String p_name) { - ERR_FAIL_V(ERR_UNAVAILABLE); + String from_path = get_absolute_path(p_from); + jstring j_from = env->NewStringUTF(from_path.utf8().get_data()); + + String to_path = get_absolute_path(p_to); + jstring j_to = env->NewStringUTF(to_path.utf8().get_data()); + + bool result = env->CallBooleanMethod(dir_access_handler, _rename, get_access_type(), j_from, j_to); + env->DeleteLocalRef(j_from); + env->DeleteLocalRef(j_to); + if (result) { + return OK; + } else { + return FAILED; + } + } else { + return ERR_UNCONFIGURED; + } } -String DirAccessJAndroid::get_filesystem_type() const { - return "APK"; +Error DirAccessJAndroid::remove(String p_name) { + if (_remove) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, ERR_UNCONFIGURED); + + String path = get_absolute_path(p_name); + jstring j_name = env->NewStringUTF(path.utf8().get_data()); + bool result = env->CallBooleanMethod(dir_access_handler, _remove, get_access_type(), j_name); + env->DeleteLocalRef(j_name); + if (result) { + return OK; + } else { + return FAILED; + } + } else { + return ERR_UNCONFIGURED; + } } uint64_t DirAccessJAndroid::get_space_left() { - return 0; + if (_get_space_left) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, 0); + return env->CallLongMethod(dir_access_handler, _get_space_left, get_access_type()); + } else { + return 0; + } } -void DirAccessJAndroid::setup(jobject p_io) { +void DirAccessJAndroid::setup(jobject p_dir_access_handler) { JNIEnv *env = get_jni_env(); - io = p_io; + dir_access_handler = env->NewGlobalRef(p_dir_access_handler); - jclass c = env->GetObjectClass(io); + jclass c = env->GetObjectClass(dir_access_handler); cls = (jclass)env->NewGlobalRef(c); - _dir_open = env->GetMethodID(cls, "dir_open", "(Ljava/lang/String;)I"); - _dir_next = env->GetMethodID(cls, "dir_next", "(I)Ljava/lang/String;"); - _dir_close = env->GetMethodID(cls, "dir_close", "(I)V"); - _dir_is_dir = env->GetMethodID(cls, "dir_is_dir", "(I)Z"); + _dir_open = env->GetMethodID(cls, "dirOpen", "(ILjava/lang/String;)I"); + _dir_next = env->GetMethodID(cls, "dirNext", "(II)Ljava/lang/String;"); + _dir_close = env->GetMethodID(cls, "dirClose", "(II)V"); + _dir_is_dir = env->GetMethodID(cls, "dirIsDir", "(II)Z"); + _dir_exists = env->GetMethodID(cls, "dirExists", "(ILjava/lang/String;)Z"); + _file_exists = env->GetMethodID(cls, "fileExists", "(ILjava/lang/String;)Z"); + _get_drive_count = env->GetMethodID(cls, "getDriveCount", "(I)I"); + _get_drive = env->GetMethodID(cls, "getDrive", "(II)Ljava/lang/String;"); + _make_dir = env->GetMethodID(cls, "makeDir", "(ILjava/lang/String;)Z"); + _get_space_left = env->GetMethodID(cls, "getSpaceLeft", "(I)J"); + _rename = env->GetMethodID(cls, "rename", "(ILjava/lang/String;Ljava/lang/String;)Z"); + _remove = env->GetMethodID(cls, "remove", "(ILjava/lang/String;)Z"); + _current_is_hidden = env->GetMethodID(cls, "isCurrentHidden", "(II)Z"); } DirAccessJAndroid::DirAccessJAndroid() { @@ -233,3 +302,26 @@ DirAccessJAndroid::DirAccessJAndroid() { DirAccessJAndroid::~DirAccessJAndroid() { list_dir_end(); } + +int DirAccessJAndroid::dir_open(String p_path) { + if (_dir_open) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, 0); + + String path = get_absolute_path(p_path); + jstring js = env->NewStringUTF(path.utf8().get_data()); + int dirId = env->CallIntMethod(dir_access_handler, _dir_open, get_access_type(), js); + env->DeleteLocalRef(js); + return dirId; + } else { + return 0; + } +} + +void DirAccessJAndroid::dir_close(int p_id) { + if (_dir_close) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND(env == nullptr); + env->CallVoidMethod(dir_access_handler, _dir_close, get_access_type(), p_id); + } +} diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index 0e1b12cb58..d469c9d317 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -32,58 +32,70 @@ #define DIR_ACCESS_JANDROID_H #include "core/io/dir_access.h" +#include "drivers/unix/dir_access_unix.h" #include "java_godot_lib_jni.h" #include <stdio.h> -class DirAccessJAndroid : public DirAccess { - static jobject io; +/// Android implementation of the DirAccess interface used to provide access to +/// ACCESS_FILESYSTEM and ACCESS_RESOURCES directory resources. +/// The implementation use jni in order to comply with Android filesystem +/// access restriction. +class DirAccessJAndroid : public DirAccessUnix { + static jobject dir_access_handler; static jclass cls; static jmethodID _dir_open; static jmethodID _dir_next; static jmethodID _dir_close; static jmethodID _dir_is_dir; - - int id = 0; - - String current_dir; - String current; - - static Ref<DirAccess> create_fs(); + static jmethodID _dir_exists; + static jmethodID _file_exists; + static jmethodID _get_drive_count; + static jmethodID _get_drive; + static jmethodID _make_dir; + static jmethodID _get_space_left; + static jmethodID _rename; + static jmethodID _remove; + static jmethodID _current_is_hidden; public: - virtual Error list_dir_begin(); ///< This starts dir listing - virtual String get_next(); - virtual bool current_is_dir() const; - virtual bool current_is_hidden() const; - virtual void list_dir_end(); ///< + virtual Error list_dir_begin() override; ///< This starts dir listing + virtual String get_next() override; + virtual bool current_is_dir() const override; + virtual bool current_is_hidden() const override; + virtual void list_dir_end() override; ///< - virtual int get_drive_count(); - virtual String get_drive(int p_drive); + virtual int get_drive_count() override; + virtual String get_drive(int p_drive) override; - virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success - virtual String get_current_dir(bool p_include_drive = true) const; ///< return current dir location + virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success - virtual bool file_exists(String p_file); - virtual bool dir_exists(String p_dir); + virtual bool file_exists(String p_file) override; + virtual bool dir_exists(String p_dir) override; - virtual Error make_dir(String p_dir); + virtual Error make_dir(String p_dir) override; + virtual Error make_dir_recursive(String p_dir) override; - virtual Error rename(String p_from, String p_to); - virtual Error remove(String p_name); + virtual Error rename(String p_from, String p_to) override; + virtual Error remove(String p_name) override; - virtual bool is_link(String p_file) { return false; } - virtual String read_link(String p_file) { return p_file; } - virtual Error create_link(String p_source, String p_target) { return FAILED; } + virtual bool is_link(String p_file) override { return false; } + virtual String read_link(String p_file) override { return p_file; } + virtual Error create_link(String p_source, String p_target) override { return FAILED; } - virtual String get_filesystem_type() const; + virtual uint64_t get_space_left() override; - uint64_t get_space_left(); - - static void setup(jobject p_io); + static void setup(jobject p_dir_access_handler); DirAccessJAndroid(); ~DirAccessJAndroid(); + +private: + int id = 0; + + int dir_open(String p_path); + void dir_close(int p_id); + String get_absolute_path(String p_path); }; #endif // DIR_ACCESS_JANDROID_H diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 560f188b82..5bbe0ffab6 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -30,10 +30,10 @@ #include "export.h" -#include "export_plugin.h" - #include "core/os/os.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export.h" +#include "export_plugin.h" void register_android_exporter() { EDITOR_DEF("export/android/android_sdk_path", ""); diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 73c6fcc7e8..2cfb152804 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -123,6 +123,7 @@ static const char *android_perms[] = { "MANAGE_ACCOUNTS", "MANAGE_APP_TOKENS", "MANAGE_DOCUMENTS", + "MANAGE_EXTERNAL_STORAGE", "MASTER_CLEAR", "MEDIA_CONTENT_CONTROL", "MODIFY_AUDIO_SETTINGS", @@ -245,8 +246,7 @@ static const char *APK_ASSETS_DIRECTORY = "res://android/build/assets"; static const char *AAB_ASSETS_DIRECTORY = "res://android/build/assetPacks/installTime/src/main/assets"; static const int DEFAULT_MIN_SDK_VERSION = 19; // Should match the value in 'platform/android/java/app/config.gradle#minSdk' -static const int DEFAULT_TARGET_SDK_VERSION = 30; // Should match the value in 'platform/android/java/app/config.gradle#targetSdk' -const String SDK_VERSION_RANGE = vformat("%s,%s,1", DEFAULT_MIN_SDK_VERSION, DEFAULT_TARGET_SDK_VERSION); +static const int DEFAULT_TARGET_SDK_VERSION = 32; // Should match the value in 'platform/android/java/app/config.gradle#targetSdk' void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { EditorExportPlatformAndroid *ea = static_cast<EditorExportPlatformAndroid *>(ud); @@ -277,6 +277,7 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { } } +#ifndef ANDROID_ENABLED // Check for devices updates String adb = get_adb_path(); if (FileAccess::exists(adb)) { @@ -388,6 +389,7 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { ea->devices_changed.set(); } } +#endif uint64_t sleep = 200; uint64_t wait = 3000000; @@ -400,6 +402,7 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { } } +#ifndef ANDROID_ENABLED if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) { String adb = get_adb_path(); if (!FileAccess::exists(adb)) { @@ -410,6 +413,7 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { args.push_back("kill-server"); OS::get_singleton()->execute(adb, args); } +#endif } String EditorExportPlatformAndroid::get_project_name(const String &p_name) const { @@ -748,10 +752,14 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared return OK; } -bool EditorExportPlatformAndroid::_has_storage_permission(const Vector<String> &p_permissions) { +bool EditorExportPlatformAndroid::_has_read_write_storage_permission(const Vector<String> &p_permissions) { return p_permissions.find("android.permission.READ_EXTERNAL_STORAGE") != -1 || p_permissions.find("android.permission.WRITE_EXTERNAL_STORAGE") != -1; } +bool EditorExportPlatformAndroid::_has_manage_external_storage_permission(const Vector<String> &p_permissions) { + return p_permissions.find("android.permission.MANAGE_EXTERNAL_STORAGE") != -1; +} + void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions) { const char **aperms = android_perms; while (*aperms) { @@ -799,7 +807,7 @@ void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPres _get_permissions(p_preset, p_give_internet, perms); for (int i = 0; i < perms.size(); i++) { String permission = perms.get(i); - if (permission == "android.permission.WRITE_EXTERNAL_STORAGE" || permission == "android.permission.READ_EXTERNAL_STORAGE") { + if (permission == "android.permission.WRITE_EXTERNAL_STORAGE" || (permission == "android.permission.READ_EXTERNAL_STORAGE" && _has_manage_external_storage_permission(perms))) { manifest_text += vformat(" <uses-permission android:name=\"%s\" android:maxSdkVersion=\"29\" />\n", permission); } else { manifest_text += vformat(" <uses-permission android:name=\"%s\" />\n", permission); @@ -807,7 +815,7 @@ void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPres } manifest_text += _get_xr_features_tag(p_preset); - manifest_text += _get_application_tag(p_preset, _has_storage_permission(perms)); + manifest_text += _get_application_tag(p_preset, _has_read_write_storage_permission(perms)); manifest_text += "</manifest>\n"; String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release")); @@ -865,7 +873,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p Vector<String> perms; // Write permissions into the perms variable. _get_permissions(p_preset, p_give_internet, perms); - bool has_storage_permission = _has_storage_permission(perms); + bool has_read_write_storage_permission = _has_read_write_storage_permission(perms); while (ofs < (uint32_t)p_manifest.size()) { uint32_t chunk = decode_uint32(&p_manifest[ofs]); @@ -949,7 +957,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p } if (tname == "application" && attrname == "requestLegacyExternalStorage") { - encode_uint32(has_storage_permission ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); + encode_uint32(has_read_write_storage_permission ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } if (tname == "application" && attrname == "allowBackup") { @@ -1682,8 +1690,13 @@ void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPres void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_options) { 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"), EXPORT_FORMAT_APK)); + + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_build/use_custom_build"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "custom_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK)); + // Using String instead of int to default to an empty string (no override) with placeholder for instructions (see GH-62465). + // This implies doing validation that the string is a proper int. + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_build/min_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_MIN_SDK_VERSION)), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_build/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_SDK_VERSION)), "")); Vector<PluginConfigAndroid> plugins_configs = get_plugins(); for (int i = 0; i < plugins_configs.size(); i++) { @@ -1710,8 +1723,6 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/min_sdk", PROPERTY_HINT_RANGE, SDK_VERSION_RANGE), DEFAULT_MIN_SDK_VERSION)); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/target_sdk", PROPERTY_HINT_RANGE, SDK_VERSION_RANGE), DEFAULT_TARGET_SDK_VERSION)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), "")); @@ -2039,7 +2050,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() { bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; - const bool custom_build_enabled = p_preset->get("custom_template/use_custom_build"); + const bool custom_build_enabled = p_preset->get("custom_build/use_custom_build"); // Look for export templates (first official, and if defined custom templates). @@ -2201,43 +2212,73 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr if (xr_mode_index != XR_MODE_OPENXR) { if (hand_tracking > XR_HAND_TRACKING_NONE) { valid = false; - err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"OpenXR\"."); + err += TTR("\"Hand Tracking\" is only valid when \"XR Mode\" is \"OpenXR\"."); err += "\n"; } if (passthrough_mode > XR_PASSTHROUGH_NONE) { valid = false; - err += TTR("\"Passthrough\" is only valid when \"Xr Mode\" is \"OpenXR\"."); + err += TTR("\"Passthrough\" is only valid when \"XR Mode\" is \"OpenXR\"."); err += "\n"; } } - if (int(p_preset->get("custom_template/export_format")) == EXPORT_FORMAT_AAB && + if (int(p_preset->get("custom_build/export_format")) == EXPORT_FORMAT_AAB && !custom_build_enabled) { valid = false; err += TTR("\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."); err += "\n"; } - // Check the min sdk version - int min_sdk_version = p_preset->get("version/min_sdk"); - if (min_sdk_version != DEFAULT_MIN_SDK_VERSION && !custom_build_enabled) { - valid = false; - err += TTR("Changing the \"Min Sdk\" is only valid when \"Use Custom Build\" is enabled."); - err += "\n"; + // Check the min sdk version. + String min_sdk_str = p_preset->get("custom_build/min_sdk"); + int min_sdk_int = DEFAULT_MIN_SDK_VERSION; + if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do. + if (!custom_build_enabled) { + valid = false; + err += TTR("\"Min SDK\" can only be overridden when \"Use Custom Build\" is enabled."); + err += "\n"; + } + if (!min_sdk_str.is_valid_int()) { + valid = false; + err += vformat(TTR("\"Min SDK\" should be a valid integer, but got \"%s\" which is invalid."), min_sdk_str); + err += "\n"; + } else { + min_sdk_int = min_sdk_str.to_int(); + if (min_sdk_int < DEFAULT_MIN_SDK_VERSION) { + valid = false; + err += vformat(TTR("\"Min SDK\" cannot be lower than %d, which is the version needed by the Godot library."), DEFAULT_MIN_SDK_VERSION); + err += "\n"; + } + } } - // Check the target sdk version - int target_sdk_version = p_preset->get("version/target_sdk"); - if (target_sdk_version != DEFAULT_TARGET_SDK_VERSION && !custom_build_enabled) { - valid = false; - err += TTR("Changing the \"Target Sdk\" is only valid when \"Use Custom Build\" is enabled."); - err += "\n"; + // Check the target sdk version. + String target_sdk_str = p_preset->get("custom_build/target_sdk"); + int target_sdk_int = DEFAULT_TARGET_SDK_VERSION; + if (!target_sdk_str.is_empty()) { // Empty means no override, nothing to do. + if (!custom_build_enabled) { + valid = false; + err += TTR("\"Target SDK\" can only be overridden when \"Use Custom Build\" is enabled."); + err += "\n"; + } + if (!target_sdk_str.is_valid_int()) { + valid = false; + err += vformat(TTR("\"Target SDK\" should be a valid integer, but got \"%s\" which is invalid."), target_sdk_str); + err += "\n"; + } else { + target_sdk_int = target_sdk_str.to_int(); + if (target_sdk_int > DEFAULT_TARGET_SDK_VERSION) { + // Warning only, so don't override `valid`. + err += vformat(TTR("\"Target SDK\" %d is higher than the default version %d. This may work, but wasn't tested and may be unstable."), target_sdk_int, DEFAULT_TARGET_SDK_VERSION); + err += "\n"; + } + } } - if (target_sdk_version < min_sdk_version) { + if (target_sdk_int < min_sdk_int) { valid = false; - err += TTR("\"Target Sdk\" version must be greater or equal to \"Min Sdk\" version."); + err += TTR("\"Target SDK\" version must be greater or equal to \"Min SDK\" version."); err += "\n"; } @@ -2326,7 +2367,7 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP } Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &export_path, EditorProgress &ep) { - int export_format = int(p_preset->get("custom_template/export_format")); + int export_format = int(p_preset->get("custom_build/export_format")); String export_label = export_format == EXPORT_FORMAT_AAB ? "AAB" : "APK"; String release_keystore = p_preset->get("keystore/release"); String release_username = p_preset->get("keystore/release_user"); @@ -2482,7 +2523,7 @@ String EditorExportPlatformAndroid::join_list(List<String> parts, const String & } Error EditorExportPlatformAndroid::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { - int export_format = int(p_preset->get("custom_template/export_format")); + int export_format = int(p_preset->get("custom_build/export_format")); bool should_sign = p_preset->get("package/signed"); return export_project_helper(p_preset, p_debug, p_path, export_format, should_sign, p_flags); } @@ -2495,7 +2536,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP EditorProgress ep("export", TTR("Exporting for Android"), 105, true); - bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build")); + bool use_custom_build = bool(p_preset->get("custom_build/use_custom_build")); bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG); bool apk_expansion = p_preset->get("apk_expansion/enable"); Vector<String> enabled_abis = get_enabled_abis(p_preset); @@ -2623,8 +2664,14 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP 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 min_sdk_version = itos(p_preset->get("version/min_sdk")); - String target_sdk_version = itos(p_preset->get("version/target_sdk")); + String min_sdk_version = p_preset->get("custom_build/min_sdk"); + if (!min_sdk_version.is_valid_int()) { + min_sdk_version = itos(DEFAULT_MIN_SDK_VERSION); + } + String target_sdk_version = p_preset->get("custom_build/target_sdk"); + if (!target_sdk_version.is_valid_int()) { + target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION); + } String enabled_abi_string = String("|").join(enabled_abis); String sign_flag = should_sign ? "true" : "false"; String zipalign_flag = "true"; @@ -3071,13 +3118,8 @@ void EditorExportPlatformAndroid::resolve_platform_feature_priorities(const Ref< } EditorExportPlatformAndroid::EditorExportPlatformAndroid() { - Ref<Image> img = memnew(Image(_android_logo)); - logo.instantiate(); - logo->create_from_image(img); - - img = Ref<Image>(memnew(Image(_android_run_icon))); - run_icon.instantiate(); - run_icon->create_from_image(img); + logo = ImageTexture::create_from_image(memnew(Image(_android_logo))); + run_icon = ImageTexture::create_from_image(memnew(Image(_android_run_icon))); devices_changed.set(); plugins_changed.set(); diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index eeb5aae0f1..8fd2f0680d 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -35,7 +35,7 @@ #include "core/io/zip_io.h" #include "core/os/os.h" -#include "editor/editor_export.h" +#include "editor/export/editor_export_platform.h" const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> @@ -116,7 +116,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so); - bool _has_storage_permission(const Vector<String> &p_permissions); + bool _has_read_write_storage_permission(const Vector<String> &p_permissions); + + bool _has_manage_external_storage_permission(const Vector<String> &p_permissions); void _get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions); diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 9a470edfdd..8d370a31a4 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -254,7 +254,7 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { return manifest_activity_text; } -String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_storage_permission) { +String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission) { int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); bool uses_xr = xr_mode_index == XR_MODE_OPENXR; String manifest_application_text = vformat( @@ -271,7 +271,7 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_ bool_to_string(p_preset->get("user_data_backup/allow")), bool_to_string(p_preset->get("package/classify_as_game")), bool_to_string(p_preset->get("package/retain_data_on_uninstall")), - bool_to_string(p_has_storage_permission)); + bool_to_string(p_has_read_write_storage_permission)); if (uses_xr) { bool hand_tracking_enabled = (int)(p_preset->get("xr_features/hand_tracking")) > XR_HAND_TRACKING_NONE; diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 109852bdfc..232b4458c6 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_GRADLE_EXPORT_UTIL_H -#define GODOT_GRADLE_EXPORT_UTIL_H +#ifndef ANDROID_GRADLE_EXPORT_UTIL_H +#define ANDROID_GRADLE_EXPORT_UTIL_H #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/zip_io.h" #include "core/os/os.h" -#include "editor/editor_export.h" +#include "editor/export/editor_export.h" const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="utf-8"?> <!--WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME--> @@ -104,6 +104,6 @@ String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset); String _get_activity_tag(const Ref<EditorExportPreset> &p_preset); -String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_storage_permission); +String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission); -#endif // GODOT_GRADLE_EXPORT_UTIL_H +#endif // ANDROID_GRADLE_EXPORT_UTIL_H diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index 4bb8a13bb6..ace7636e6c 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -34,14 +34,20 @@ AAssetManager *FileAccessAndroid::asset_manager = nullptr; -Ref<FileAccess> FileAccessAndroid::create_android() { - return memnew(FileAccessAndroid); +String FileAccessAndroid::get_path() const { + return path_src; +} + +String FileAccessAndroid::get_path_absolute() const { + return absolute_path; } Error FileAccessAndroid::_open(const String &p_path, int p_mode_flags) { _close(); + path_src = p_path; String path = fix_path(p_path).simplify_path(); + absolute_path = path; if (path.begins_with("/")) { path = path.substr(1, path.length()); } else if (path.begins_with("res://")) { @@ -134,7 +140,7 @@ uint64_t FileAccessAndroid::get_buffer(uint8_t *p_dst, uint64_t p_length) const } Error FileAccessAndroid::get_error() const { - return eof ? ERR_FILE_EOF : OK; //not sure what else it may happen + return eof ? ERR_FILE_EOF : OK; // not sure what else it may happen } void FileAccessAndroid::flush() { diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index c16f74ac43..e6fd8c857b 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -37,11 +37,12 @@ #include <stdio.h> class FileAccessAndroid : public FileAccess { - static Ref<FileAccess> create_android(); mutable AAsset *asset = nullptr; mutable uint64_t len = 0; mutable uint64_t pos = 0; mutable bool eof = false; + String absolute_path; + String path_src; void _close(); @@ -51,6 +52,11 @@ public: virtual Error _open(const String &p_path, int p_mode_flags); // open a file virtual bool is_open() const; // true when file is open + /// returns the path for the current open file + virtual String get_path() const; + /// returns the absolute path for the current open file + virtual String get_path_absolute() const; + virtual void seek(uint64_t p_position); // seek to a given position virtual void seek_end(int64_t p_position = 0); // seek from the end of file virtual uint64_t get_position() const; // get position in the file diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp new file mode 100644 index 0000000000..733d92f741 --- /dev/null +++ b/platform/android/file_access_filesystem_jandroid.cpp @@ -0,0 +1,329 @@ +/*************************************************************************/ +/* file_access_filesystem_jandroid.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "file_access_filesystem_jandroid.h" +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "thread_jandroid.h" +#include <unistd.h> + +jobject FileAccessFilesystemJAndroid::file_access_handler = nullptr; +jclass FileAccessFilesystemJAndroid::cls; + +jmethodID FileAccessFilesystemJAndroid::_file_open = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_get_size = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_seek = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_seek_end = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_read = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_tell = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_eof = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_close = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_write = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_flush = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_exists = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_last_modified = nullptr; + +String FileAccessFilesystemJAndroid::get_path() const { + return path_src; +} + +String FileAccessFilesystemJAndroid::get_path_absolute() const { + return absolute_path; +} + +Error FileAccessFilesystemJAndroid::_open(const String &p_path, int p_mode_flags) { + if (is_open()) { + _close(); + } + + if (_file_open) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, ERR_UNCONFIGURED); + + String path = fix_path(p_path).simplify_path(); + jstring js = env->NewStringUTF(path.utf8().get_data()); + int res = env->CallIntMethod(file_access_handler, _file_open, js, p_mode_flags); + env->DeleteLocalRef(js); + + if (res <= 0) { + switch (res) { + case 0: + default: + return ERR_FILE_CANT_OPEN; + + case -1: + return ERR_FILE_NOT_FOUND; + } + } + + id = res; + path_src = p_path; + absolute_path = path; + return OK; + } else { + return ERR_UNCONFIGURED; + } +} + +void FileAccessFilesystemJAndroid::_close() { + if (!is_open()) { + return; + } + + if (_file_close) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND(env == nullptr); + env->CallVoidMethod(file_access_handler, _file_close, id); + } + id = 0; +} + +bool FileAccessFilesystemJAndroid::is_open() const { + return id != 0; +} + +void FileAccessFilesystemJAndroid::seek(uint64_t p_position) { + if (_file_seek) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND(env == nullptr); + ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); + env->CallVoidMethod(file_access_handler, _file_seek, id, p_position); + } +} + +void FileAccessFilesystemJAndroid::seek_end(int64_t p_position) { + if (_file_seek_end) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND(env == nullptr); + ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); + env->CallVoidMethod(file_access_handler, _file_seek_end, id, p_position); + } +} + +uint64_t FileAccessFilesystemJAndroid::get_position() const { + if (_file_tell) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, 0); + ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); + return env->CallLongMethod(file_access_handler, _file_tell, id); + } else { + return 0; + } +} + +uint64_t FileAccessFilesystemJAndroid::get_length() const { + if (_file_get_size) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, 0); + ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); + return env->CallLongMethod(file_access_handler, _file_get_size, id); + } else { + return 0; + } +} + +bool FileAccessFilesystemJAndroid::eof_reached() const { + if (_file_eof) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, false); + ERR_FAIL_COND_V_MSG(!is_open(), false, "File must be opened before use."); + return env->CallBooleanMethod(file_access_handler, _file_eof, id); + } else { + return false; + } +} + +uint8_t FileAccessFilesystemJAndroid::get_8() const { + ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); + uint8_t byte; + get_buffer(&byte, 1); + return byte; +} + +String FileAccessFilesystemJAndroid::get_line() const { + ERR_FAIL_COND_V_MSG(!is_open(), String(), "File must be opened before use."); + + const size_t buffer_size_limit = 2048; + const uint64_t file_size = get_length(); + const uint64_t start_position = get_position(); + + String result; + LocalVector<uint8_t> line_buffer; + size_t current_buffer_size = 0; + uint64_t line_buffer_position = 0; + + while (true) { + size_t line_buffer_size = MIN(buffer_size_limit, file_size - get_position()); + if (line_buffer_size <= 0) { + break; + } + + current_buffer_size += line_buffer_size; + line_buffer.resize(current_buffer_size); + + uint64_t bytes_read = get_buffer(&line_buffer[line_buffer_position], current_buffer_size - line_buffer_position); + if (bytes_read <= 0) { + break; + } + + for (; bytes_read > 0; line_buffer_position++, bytes_read--) { + uint8_t elem = line_buffer[line_buffer_position]; + if (elem == '\n' || elem == '\0') { + // Found the end of the line + const_cast<FileAccessFilesystemJAndroid *>(this)->seek(start_position + line_buffer_position + 1); + if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position)) { + return String(); + } + return result; + } + } + } + + if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position)) { + return String(); + } + return result; +} + +uint64_t FileAccessFilesystemJAndroid::get_buffer(uint8_t *p_dst, uint64_t p_length) const { + if (_file_read) { + ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); + if (p_length == 0) { + return 0; + } + + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, 0); + + jobject j_buffer = env->NewDirectByteBuffer(p_dst, p_length); + int length = env->CallIntMethod(file_access_handler, _file_read, id, j_buffer); + env->DeleteLocalRef(j_buffer); + return length; + } else { + return 0; + } +} + +void FileAccessFilesystemJAndroid::store_8(uint8_t p_dest) { + store_buffer(&p_dest, 1); +} + +void FileAccessFilesystemJAndroid::store_buffer(const uint8_t *p_src, uint64_t p_length) { + if (_file_write) { + ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); + if (p_length == 0) { + return; + } + + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND(env == nullptr); + + jobject j_buffer = env->NewDirectByteBuffer((void *)p_src, p_length); + env->CallVoidMethod(file_access_handler, _file_write, id, j_buffer); + env->DeleteLocalRef(j_buffer); + } +} + +Error FileAccessFilesystemJAndroid::get_error() const { + if (eof_reached()) { + return ERR_FILE_EOF; + } + return OK; +} + +void FileAccessFilesystemJAndroid::flush() { + if (_file_flush) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND(env == nullptr); + ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); + env->CallVoidMethod(file_access_handler, _file_flush, id); + } +} + +bool FileAccessFilesystemJAndroid::file_exists(const String &p_path) { + if (_file_exists) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, false); + + String path = fix_path(p_path).simplify_path(); + jstring js = env->NewStringUTF(path.utf8().get_data()); + bool result = env->CallBooleanMethod(file_access_handler, _file_exists, js); + env->DeleteLocalRef(js); + return result; + } else { + return false; + } +} + +uint64_t FileAccessFilesystemJAndroid::_get_modified_time(const String &p_file) { + if (_file_last_modified) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, false); + + String path = fix_path(p_file).simplify_path(); + jstring js = env->NewStringUTF(path.utf8().get_data()); + uint64_t result = env->CallLongMethod(file_access_handler, _file_last_modified, js); + env->DeleteLocalRef(js); + return result; + } else { + return 0; + } +} + +void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) { + JNIEnv *env = get_jni_env(); + file_access_handler = env->NewGlobalRef(p_file_access_handler); + + jclass c = env->GetObjectClass(file_access_handler); + cls = (jclass)env->NewGlobalRef(c); + + _file_open = env->GetMethodID(cls, "fileOpen", "(Ljava/lang/String;I)I"); + _file_get_size = env->GetMethodID(cls, "fileGetSize", "(I)J"); + _file_tell = env->GetMethodID(cls, "fileGetPosition", "(I)J"); + _file_eof = env->GetMethodID(cls, "isFileEof", "(I)Z"); + _file_seek = env->GetMethodID(cls, "fileSeek", "(IJ)V"); + _file_seek_end = env->GetMethodID(cls, "fileSeekFromEnd", "(IJ)V"); + _file_read = env->GetMethodID(cls, "fileRead", "(ILjava/nio/ByteBuffer;)I"); + _file_close = env->GetMethodID(cls, "fileClose", "(I)V"); + _file_write = env->GetMethodID(cls, "fileWrite", "(ILjava/nio/ByteBuffer;)V"); + _file_flush = env->GetMethodID(cls, "fileFlush", "(I)V"); + _file_exists = env->GetMethodID(cls, "fileExists", "(Ljava/lang/String;)Z"); + _file_last_modified = env->GetMethodID(cls, "fileLastModified", "(Ljava/lang/String;)J"); +} + +FileAccessFilesystemJAndroid::FileAccessFilesystemJAndroid() { + id = 0; +} + +FileAccessFilesystemJAndroid::~FileAccessFilesystemJAndroid() { + if (is_open()) { + _close(); + } +} diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h new file mode 100644 index 0000000000..7deb8de37b --- /dev/null +++ b/platform/android/file_access_filesystem_jandroid.h @@ -0,0 +1,98 @@ +/*************************************************************************/ +/* file_access_filesystem_jandroid.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef FILE_ACCESS_FILESYSTEM_JANDROID_H +#define FILE_ACCESS_FILESYSTEM_JANDROID_H + +#include "core/io/file_access.h" +#include "java_godot_lib_jni.h" + +class FileAccessFilesystemJAndroid : public FileAccess { + static jobject file_access_handler; + static jclass cls; + + static jmethodID _file_open; + static jmethodID _file_get_size; + static jmethodID _file_seek; + static jmethodID _file_seek_end; + static jmethodID _file_tell; + static jmethodID _file_eof; + static jmethodID _file_read; + static jmethodID _file_write; + static jmethodID _file_flush; + static jmethodID _file_close; + static jmethodID _file_exists; + static jmethodID _file_last_modified; + + int id; + String absolute_path; + String path_src; + + void _close(); ///< close a file + +public: + virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file + virtual bool is_open() const override; ///< true when file is open + + /// returns the path for the current open file + virtual String get_path() const override; + /// returns the absolute path for the current open file + virtual String get_path_absolute() const override; + + virtual void seek(uint64_t p_position) override; ///< seek to a given position + virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file + virtual uint64_t get_position() const override; ///< get position in the file + virtual uint64_t get_length() const override; ///< get size of the file + + virtual bool eof_reached() const override; ///< reading passed EOF + + virtual uint8_t get_8() const override; ///< get a byte + virtual String get_line() const override; ///< get a line + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; + + virtual Error get_error() const override; ///< get last error + + virtual void flush() override; + virtual void store_8(uint8_t p_dest) override; ///< store a byte + virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; + + virtual bool file_exists(const String &p_path) override; ///< return true if a file exists + + static void setup(jobject p_file_access_handler); + + virtual uint64_t _get_modified_time(const String &p_file) override; + virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; } + + FileAccessFilesystemJAndroid(); + ~FileAccessFilesystemJAndroid(); +}; + +#endif // FILE_ACCESS_FILESYSTEM_JANDROID_H diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index c98e8f1d55..2d4c4763a2 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -59,6 +59,7 @@ android:theme="@style/GodotAppSplashTheme" android:launchMode="singleTask" android:excludeFromRecents="false" + android:exported="true" android:screenOrientation="landscape" android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode" android:resizeableActivity="false" diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index 73a412a2b0..fbd97fae0b 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -1,14 +1,14 @@ ext.versions = [ androidGradlePlugin: '7.0.3', - compileSdk : 31, + compileSdk : 32, minSdk : 19, // Also update 'platform/android/java/lib/AndroidManifest.xml#minSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION' - targetSdk : 30, // Also update 'platform/android/java/lib/AndroidManifest.xml#targetSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION' - buildTools : '30.0.3', + targetSdk : 32, // Also update 'platform/android/java/lib/AndroidManifest.xml#targetSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION' + buildTools : '32.0.0', kotlinVersion : '1.6.21', fragmentVersion : '1.3.6', nexusPublishVersion: '1.1.0', javaVersion : 11, - ndkVersion : '21.4.7075529' // Also update 'platform/android/detect.py#get_project_ndk_version()' when this is updated. + ndkVersion : '23.2.8568313' // Also update 'platform/android/detect.py#get_ndk_version()' when this is updated. ] diff --git a/platform/android/java/editor/build.gradle b/platform/android/java/editor/build.gradle index dd167c3880..729966ee69 100644 --- a/platform/android/java/editor/build.gradle +++ b/platform/android/java/editor/build.gradle @@ -23,8 +23,7 @@ android { versionCode getGodotLibraryVersionCode() versionName getGodotLibraryVersionName() minSdkVersion versions.minSdk - //noinspection ExpiredTargetSdkVersion - Restrict to version 29 until https://github.com/godotengine/godot/pull/51815 is submitted - targetSdkVersion 29 // versions.targetSdk + targetSdkVersion versions.targetSdk missingDimensionStrategy 'products', 'editor' } diff --git a/platform/android/java/editor/src/main/AndroidManifest.xml b/platform/android/java/editor/src/main/AndroidManifest.xml index 659caf7ab4..abf506a83c 100644 --- a/platform/android/java/editor/src/main/AndroidManifest.xml +++ b/platform/android/java/editor/src/main/AndroidManifest.xml @@ -14,8 +14,12 @@ android:glEsVersion="0x00020000" android:required="true" /> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" + tools:ignore="ScopedStorage" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" + android:maxSdkVersion="29"/> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" + android:maxSdkVersion="29"/> <uses-permission android:name="android.permission.INTERNET" /> <application @@ -49,6 +53,7 @@ android:process=":GodotEditor" android:launchMode="singleTask" android:screenOrientation="userLandscape" + android:exported="false" android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"> <layout android:defaultHeight="@dimen/editor_default_window_height" android:defaultWidth="@dimen/editor_default_window_width" /> @@ -60,6 +65,7 @@ android:label="@string/godot_project_name_string" android:process=":GodotGame" android:launchMode="singleTask" + android:exported="false" android:screenOrientation="userLandscape" android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"> <layout android:defaultHeight="@dimen/editor_default_window_height" diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt index a1ade722e8..740f3f48d3 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt @@ -30,10 +30,14 @@ package org.godotengine.editor +import android.Manifest import android.content.Intent +import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.os.Debug +import android.os.Environment +import android.widget.Toast import androidx.window.layout.WindowMetricsCalculator import org.godotengine.godot.FullScreenGodotApp import org.godotengine.godot.utils.PermissionsUtil @@ -68,7 +72,7 @@ open class GodotEditor : FullScreenGodotApp() { val params = intent.getStringArrayExtra(COMMAND_LINE_PARAMS) updateCommandLineParams(params) - if (BuildConfig.BUILD_TYPE == "debug" && WAIT_FOR_DEBUGGER) { + if (BuildConfig.BUILD_TYPE == "dev" && WAIT_FOR_DEBUGGER) { Debug.waitForDebugger() } @@ -143,4 +147,50 @@ open class GodotEditor : FullScreenGodotApp() { * The Godot Android Editor sets its own orientation via its AndroidManifest */ protected open fun overrideOrientationRequest() = true + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + // Check if we got the MANAGE_EXTERNAL_STORAGE permission + if (requestCode == PermissionsUtil.REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (!Environment.isExternalStorageManager()) { + Toast.makeText( + this, + R.string.denied_storage_permission_error_msg, + Toast.LENGTH_LONG + ).show() + } + } + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array<String?>, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + // Check if we got access to the necessary storage permissions + if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + var hasReadAccess = false + var hasWriteAccess = false + for (i in permissions.indices) { + if (Manifest.permission.READ_EXTERNAL_STORAGE == permissions[i] && grantResults[i] == PackageManager.PERMISSION_GRANTED) { + hasReadAccess = true + } + if (Manifest.permission.WRITE_EXTERNAL_STORAGE == permissions[i] && grantResults[i] == PackageManager.PERMISSION_GRANTED) { + hasWriteAccess = true + } + } + if (!hasReadAccess || !hasWriteAccess) { + Toast.makeText( + this, + R.string.denied_storage_permission_error_msg, + Toast.LENGTH_LONG + ).show() + } + } + } + } } diff --git a/platform/android/java/editor/src/main/res/values/strings.xml b/platform/android/java/editor/src/main/res/values/strings.xml index e8ce34f34d..837a5d62e1 100644 --- a/platform/android/java/editor/src/main/res/values/strings.xml +++ b/platform/android/java/editor/src/main/res/values/strings.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <string name="godot_editor_name_string">Godot Editor 4.x</string> + + <string name="denied_storage_permission_error_msg">Missing storage access permission!</string> </resources> diff --git a/platform/android/java/lib/AndroidManifest.xml b/platform/android/java/lib/AndroidManifest.xml index 90dc61a6ac..79b5aadf2a 100644 --- a/platform/android/java/lib/AndroidManifest.xml +++ b/platform/android/java/lib/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionName="1.0"> <!-- Should match the mindSdk and targetSdk values in platform/android/java/app/config.gradle --> - <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="30" /> + <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="32" /> <application> 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 cafae94d62..28e689e63a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -34,6 +34,8 @@ import static android.content.Context.MODE_PRIVATE; import static android.content.Context.WINDOW_SERVICE; import org.godotengine.godot.input.GodotEditText; +import org.godotengine.godot.io.directory.DirectoryAccessHandler; +import org.godotengine.godot.io.file.FileAccessHandler; import org.godotengine.godot.plugin.GodotPlugin; import org.godotengine.godot.plugin.GodotPluginRegistry; import org.godotengine.godot.tts.GodotTTS; @@ -164,9 +166,9 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC private Sensor mMagnetometer; private Sensor mGyroscope; - public static GodotIO io; - public static GodotNetUtils netUtils; - public static GodotTTS tts; + public GodotIO io; + public GodotNetUtils netUtils; + public GodotTTS tts; public interface ResultCallback { void callback(int requestCode, int resultCode, Intent data); @@ -458,16 +460,26 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC final Activity activity = getActivity(); io = new GodotIO(activity); - GodotLib.io = io; netUtils = new GodotNetUtils(activity); tts = new GodotTTS(activity); + Context context = getContext(); + DirectoryAccessHandler directoryAccessHandler = new DirectoryAccessHandler(context); + FileAccessHandler fileAccessHandler = new FileAccessHandler(context); mSensorManager = (SensorManager)activity.getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mGravity = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); - GodotLib.initialize(activity, this, activity.getAssets(), use_apk_expansion); + GodotLib.initialize(activity, + this, + activity.getAssets(), + io, + netUtils, + directoryAccessHandler, + fileAccessHandler, + use_apk_expansion, + tts); result_callback = null; diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index a8e3669ac6..0434efdf4c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -36,7 +36,6 @@ import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.content.res.AssetManager; import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; @@ -46,12 +45,10 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; -import android.util.SparseArray; import android.view.Display; import android.view.DisplayCutout; import android.view.WindowInsets; -import java.io.IOException; import java.util.List; import java.util.Locale; @@ -60,7 +57,6 @@ import java.util.Locale; public class GodotIO { private static final String TAG = GodotIO.class.getSimpleName(); - private final AssetManager am; private final Activity activity; private final String uniqueId; GodotEditText edit; @@ -73,100 +69,8 @@ public class GodotIO { final int SCREEN_SENSOR_PORTRAIT = 5; final int SCREEN_SENSOR = 6; - ///////////////////////// - /// DIRECTORIES - ///////////////////////// - - static class AssetDir { - public String[] files; - public int current; - public String path; - } - - private int last_dir_id = 1; - - private final SparseArray<AssetDir> dirs; - - public int dir_open(String path) { - AssetDir ad = new AssetDir(); - ad.current = 0; - ad.path = path; - - try { - ad.files = am.list(path); - // no way to find path is directory or file exactly. - // but if ad.files.length==0, then it's an empty directory or file. - if (ad.files.length == 0) { - return -1; - } - } catch (IOException e) { - System.out.printf("Exception on dir_open: %s\n", e); - return -1; - } - - ++last_dir_id; - dirs.put(last_dir_id, ad); - - return last_dir_id; - } - - public boolean dir_is_dir(int id) { - if (dirs.get(id) == null) { - System.out.printf("dir_next: invalid dir id: %d\n", id); - return false; - } - AssetDir ad = dirs.get(id); - //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length); - int idx = ad.current; - if (idx > 0) - idx--; - - if (idx >= ad.files.length) - return false; - String fname = ad.files[idx]; - - try { - if (ad.path.equals("")) - am.open(fname); - else - am.open(ad.path + "/" + fname); - return false; - } catch (Exception e) { - return true; - } - } - - public String dir_next(int id) { - if (dirs.get(id) == null) { - System.out.printf("dir_next: invalid dir id: %d\n", id); - return ""; - } - - AssetDir ad = dirs.get(id); - //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length); - - if (ad.current >= ad.files.length) { - ad.current++; - return ""; - } - String r = ad.files[ad.current]; - ad.current++; - return r; - } - - public void dir_close(int id) { - if (dirs.get(id) == null) { - System.out.printf("dir_close: invalid dir id: %d\n", id); - return; - } - - dirs.remove(id); - } - GodotIO(Activity p_activity) { - am = p_activity.getAssets(); activity = p_activity; - dirs = new SparseArray<>(); String androidId = Settings.Secure.getString(activity.getContentResolver(), Settings.Secure.ANDROID_ID); if (androidId == null) { diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 1f8f8c82a6..e2ae62d9cf 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -31,8 +31,13 @@ package org.godotengine.godot; import org.godotengine.godot.gl.GodotRenderer; +import org.godotengine.godot.io.directory.DirectoryAccessHandler; +import org.godotengine.godot.io.file.FileAccessHandler; +import org.godotengine.godot.tts.GodotTTS; +import org.godotengine.godot.utils.GodotNetUtils; import android.app.Activity; +import android.content.res.AssetManager; import android.hardware.SensorEvent; import android.view.Surface; @@ -42,8 +47,6 @@ import javax.microedition.khronos.opengles.GL10; * Wrapper for native library */ public class GodotLib { - public static GodotIO io; - static { System.loadLibrary("godot_android"); } @@ -51,7 +54,15 @@ public class GodotLib { /** * Invoked on the main thread to initialize Godot native layer. */ - public static native void initialize(Activity activity, Godot p_instance, Object p_asset_manager, boolean use_apk_expansion); + public static native void initialize(Activity activity, + Godot p_instance, + AssetManager p_asset_manager, + GodotIO godotIO, + GodotNetUtils netUtils, + DirectoryAccessHandler directoryAccessHandler, + FileAccessHandler fileAccessHandler, + boolean use_apk_expansion, + GodotTTS tts); /** * Invoked on the main thread to clean up Godot native layer. @@ -114,11 +125,6 @@ public class GodotLib { public static native void doubleTap(int buttonMask, int x, int y); /** - * Forward scroll events from the main thread to the GL thread. - */ - public static native void scroll(int x, int y); - - /** * Forward accelerometer sensor events from the main thread to the GL thread. * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) */ diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java index ac13cad23e..778efa914a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java @@ -80,15 +80,6 @@ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener } @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - //Log.i("GodotGesture", "onScroll"); - final int x = Math.round(distanceX); - final int y = Math.round(distanceY); - GodotLib.scroll(x, y); - return true; - } - - @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { //Log.i("GodotGesture", "onFling"); return true; diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt b/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt new file mode 100644 index 0000000000..c9282dd247 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt @@ -0,0 +1,113 @@ +/*************************************************************************/ +/* StorageScope.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io + +import android.content.Context +import android.os.Build +import android.os.Environment +import java.io.File + +/** + * Represents the different storage scopes. + */ +internal enum class StorageScope { + /** + * Covers internal and external directories accessible to the app without restrictions. + */ + APP, + + /** + * Covers shared directories (from Android 10 and higher). + */ + SHARED, + + /** + * Everything else.. + */ + UNKNOWN; + + class Identifier(context: Context) { + + private val internalAppDir: String? = context.filesDir.canonicalPath + private val internalCacheDir: String? = context.cacheDir.canonicalPath + private val externalAppDir: String? = context.getExternalFilesDir(null)?.canonicalPath + private val sharedDir : String? = Environment.getExternalStorageDirectory().canonicalPath + private val downloadsSharedDir: String? = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).canonicalPath + private val documentsSharedDir: String? = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).canonicalPath + + /** + * Determines which [StorageScope] the given path falls under. + */ + fun identifyStorageScope(path: String?): StorageScope { + if (path == null) { + return UNKNOWN + } + + val pathFile = File(path) + if (!pathFile.isAbsolute) { + return UNKNOWN + } + + val canonicalPathFile = pathFile.canonicalPath + + if (internalAppDir != null && canonicalPathFile.startsWith(internalAppDir)) { + return APP + } + + if (internalCacheDir != null && canonicalPathFile.startsWith(internalCacheDir)) { + return APP + } + + if (externalAppDir != null && canonicalPathFile.startsWith(externalAppDir)) { + return APP + } + + if (sharedDir != null && canonicalPathFile.startsWith(sharedDir)) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + // Before R, apps had access to shared storage so long as they have the right + // permissions (and flag on Q). + return APP + } + + // Post R, access is limited based on the target destination + // 'Downloads' and 'Documents' are still accessible + if ((downloadsSharedDir != null && canonicalPathFile.startsWith(downloadsSharedDir)) + || (documentsSharedDir != null && canonicalPathFile.startsWith(documentsSharedDir))) { + return APP + } + + return SHARED + } + + return UNKNOWN + } + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/directory/AssetsDirectoryAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/directory/AssetsDirectoryAccess.kt new file mode 100644 index 0000000000..098b10ae36 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/directory/AssetsDirectoryAccess.kt @@ -0,0 +1,177 @@ +/*************************************************************************/ +/* AssetsDirectoryAccess.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io.directory + +import android.content.Context +import android.util.Log +import android.util.SparseArray +import org.godotengine.godot.io.directory.DirectoryAccessHandler.Companion.INVALID_DIR_ID +import org.godotengine.godot.io.directory.DirectoryAccessHandler.Companion.STARTING_DIR_ID +import java.io.File +import java.io.IOException + +/** + * Handles directories access within the Android assets directory. + */ +internal class AssetsDirectoryAccess(context: Context) : DirectoryAccessHandler.DirectoryAccess { + + companion object { + private val TAG = AssetsDirectoryAccess::class.java.simpleName + } + + private data class AssetDir(val path: String, val files: Array<String>, var current: Int = 0) + + private val assetManager = context.assets + + private var lastDirId = STARTING_DIR_ID + private val dirs = SparseArray<AssetDir>() + + private fun getAssetsPath(originalPath: String): String { + if (originalPath.startsWith(File.separatorChar)) { + return originalPath.substring(1) + } + return originalPath + } + + override fun hasDirId(dirId: Int) = dirs.indexOfKey(dirId) >= 0 + + override fun dirOpen(path: String): Int { + val assetsPath = getAssetsPath(path) ?: return INVALID_DIR_ID + try { + val files = assetManager.list(assetsPath) ?: return INVALID_DIR_ID + // Empty directories don't get added to the 'assets' directory, so + // if ad.files.length > 0 ==> path is directory + // if ad.files.length == 0 ==> path is file + if (files.isEmpty()) { + return INVALID_DIR_ID + } + + val ad = AssetDir(assetsPath, files) + + dirs.put(++lastDirId, ad) + return lastDirId + } catch (e: IOException) { + Log.e(TAG, "Exception on dirOpen", e) + return INVALID_DIR_ID + } + } + + override fun dirExists(path: String): Boolean { + val assetsPath = getAssetsPath(path) + try { + val files = assetManager.list(assetsPath) ?: return false + // Empty directories don't get added to the 'assets' directory, so + // if ad.files.length > 0 ==> path is directory + // if ad.files.length == 0 ==> path is file + return files.isNotEmpty() + } catch (e: IOException) { + Log.e(TAG, "Exception on dirExists", e) + return false + } + } + + override fun fileExists(path: String): Boolean { + val assetsPath = getAssetsPath(path) ?: return false + try { + val files = assetManager.list(assetsPath) ?: return false + // Empty directories don't get added to the 'assets' directory, so + // if ad.files.length > 0 ==> path is directory + // if ad.files.length == 0 ==> path is file + return files.isEmpty() + } catch (e: IOException) { + Log.e(TAG, "Exception on fileExists", e) + return false + } + } + + override fun dirIsDir(dirId: Int): Boolean { + val ad: AssetDir = dirs[dirId] + + var idx = ad.current + if (idx > 0) { + idx-- + } + + if (idx >= ad.files.size) { + return false + } + + val fileName = ad.files[idx] + // List the contents of $fileName. If it's a file, it will be empty, otherwise it'll be a + // directory + val filePath = if (ad.path == "") fileName else "${ad.path}/${fileName}" + val fileContents = assetManager.list(filePath) + return (fileContents?.size?: 0) > 0 + } + + override fun isCurrentHidden(dirId: Int): Boolean { + val ad = dirs[dirId] + + var idx = ad.current + if (idx > 0) { + idx-- + } + + if (idx >= ad.files.size) { + return false + } + + val fileName = ad.files[idx] + return fileName.startsWith('.') + } + + override fun dirNext(dirId: Int): String { + val ad: AssetDir = dirs[dirId] + + if (ad.current >= ad.files.size) { + ad.current++ + return "" + } + + return ad.files[ad.current++] + } + + override fun dirClose(dirId: Int) { + dirs.remove(dirId) + } + + override fun getDriveCount() = 0 + + override fun getDrive(drive: Int) = "" + + override fun makeDir(dir: String) = false + + override fun getSpaceLeft() = 0L + + override fun rename(from: String, to: String) = false + + override fun remove(filename: String) = false +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt new file mode 100644 index 0000000000..fedcf4843f --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/directory/DirectoryAccessHandler.kt @@ -0,0 +1,224 @@ +/*************************************************************************/ +/* DirectoryAccessHandler.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io.directory + +import android.content.Context +import android.util.Log +import org.godotengine.godot.io.directory.DirectoryAccessHandler.AccessType.ACCESS_FILESYSTEM +import org.godotengine.godot.io.directory.DirectoryAccessHandler.AccessType.ACCESS_RESOURCES + +/** + * Handles files and directories access and manipulation for the Android platform + */ +class DirectoryAccessHandler(context: Context) { + + companion object { + private val TAG = DirectoryAccessHandler::class.java.simpleName + + internal const val INVALID_DIR_ID = -1 + internal const val STARTING_DIR_ID = 1 + + private fun getAccessTypeFromNative(accessType: Int): AccessType? { + return when (accessType) { + ACCESS_RESOURCES.nativeValue -> ACCESS_RESOURCES + ACCESS_FILESYSTEM.nativeValue -> ACCESS_FILESYSTEM + else -> null + } + } + } + + private enum class AccessType(val nativeValue: Int) { + ACCESS_RESOURCES(0), ACCESS_FILESYSTEM(2) + } + + internal interface DirectoryAccess { + fun dirOpen(path: String): Int + fun dirNext(dirId: Int): String + fun dirClose(dirId: Int) + fun dirIsDir(dirId: Int): Boolean + fun dirExists(path: String): Boolean + fun fileExists(path: String): Boolean + fun hasDirId(dirId: Int): Boolean + fun isCurrentHidden(dirId: Int): Boolean + fun getDriveCount() : Int + fun getDrive(drive: Int): String + fun makeDir(dir: String): Boolean + fun getSpaceLeft(): Long + fun rename(from: String, to: String): Boolean + fun remove(filename: String): Boolean + } + + private val assetsDirAccess = AssetsDirectoryAccess(context) + private val fileSystemDirAccess = FilesystemDirectoryAccess(context) + + private fun hasDirId(accessType: AccessType, dirId: Int): Boolean { + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.hasDirId(dirId) + ACCESS_FILESYSTEM -> fileSystemDirAccess.hasDirId(dirId) + } + } + + fun dirOpen(nativeAccessType: Int, path: String?): Int { + val accessType = getAccessTypeFromNative(nativeAccessType) + if (path == null || accessType == null) { + return INVALID_DIR_ID + } + + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.dirOpen(path) + ACCESS_FILESYSTEM -> fileSystemDirAccess.dirOpen(path) + } + } + + fun dirNext(nativeAccessType: Int, dirId: Int): String { + val accessType = getAccessTypeFromNative(nativeAccessType) + if (accessType == null || !hasDirId(accessType, dirId)) { + Log.w(TAG, "dirNext: Invalid dir id: $dirId") + return "" + } + + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.dirNext(dirId) + ACCESS_FILESYSTEM -> fileSystemDirAccess.dirNext(dirId) + } + } + + fun dirClose(nativeAccessType: Int, dirId: Int) { + val accessType = getAccessTypeFromNative(nativeAccessType) + if (accessType == null || !hasDirId(accessType, dirId)) { + Log.w(TAG, "dirClose: Invalid dir id: $dirId") + return + } + + when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.dirClose(dirId) + ACCESS_FILESYSTEM -> fileSystemDirAccess.dirClose(dirId) + } + } + + fun dirIsDir(nativeAccessType: Int, dirId: Int): Boolean { + val accessType = getAccessTypeFromNative(nativeAccessType) + if (accessType == null || !hasDirId(accessType, dirId)) { + Log.w(TAG, "dirIsDir: Invalid dir id: $dirId") + return false + } + + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.dirIsDir(dirId) + ACCESS_FILESYSTEM -> fileSystemDirAccess.dirIsDir(dirId) + } + } + + fun isCurrentHidden(nativeAccessType: Int, dirId: Int): Boolean { + val accessType = getAccessTypeFromNative(nativeAccessType) + if (accessType == null || !hasDirId(accessType, dirId)) { + return false + } + + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.isCurrentHidden(dirId) + ACCESS_FILESYSTEM -> fileSystemDirAccess.isCurrentHidden(dirId) + } + } + + fun dirExists(nativeAccessType: Int, path: String?): Boolean { + val accessType = getAccessTypeFromNative(nativeAccessType) + if (path == null || accessType == null) { + return false + } + + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.dirExists(path) + ACCESS_FILESYSTEM -> fileSystemDirAccess.dirExists(path) + } + } + + fun fileExists(nativeAccessType: Int, path: String?): Boolean { + val accessType = getAccessTypeFromNative(nativeAccessType) + if (path == null || accessType == null) { + return false + } + + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.fileExists(path) + ACCESS_FILESYSTEM -> fileSystemDirAccess.fileExists(path) + } + } + + fun getDriveCount(nativeAccessType: Int): Int { + val accessType = getAccessTypeFromNative(nativeAccessType) ?: return 0 + return when(accessType) { + ACCESS_RESOURCES -> assetsDirAccess.getDriveCount() + ACCESS_FILESYSTEM -> fileSystemDirAccess.getDriveCount() + } + } + + fun getDrive(nativeAccessType: Int, drive: Int): String { + val accessType = getAccessTypeFromNative(nativeAccessType) ?: return "" + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.getDrive(drive) + ACCESS_FILESYSTEM -> fileSystemDirAccess.getDrive(drive) + } + } + + fun makeDir(nativeAccessType: Int, dir: String): Boolean { + val accessType = getAccessTypeFromNative(nativeAccessType) ?: return false + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.makeDir(dir) + ACCESS_FILESYSTEM -> fileSystemDirAccess.makeDir(dir) + } + } + + fun getSpaceLeft(nativeAccessType: Int): Long { + val accessType = getAccessTypeFromNative(nativeAccessType) ?: return 0L + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.getSpaceLeft() + ACCESS_FILESYSTEM -> fileSystemDirAccess.getSpaceLeft() + } + } + + fun rename(nativeAccessType: Int, from: String, to: String): Boolean { + val accessType = getAccessTypeFromNative(nativeAccessType) ?: return false + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.rename(from, to) + ACCESS_FILESYSTEM -> fileSystemDirAccess.rename(from, to) + } + } + + fun remove(nativeAccessType: Int, filename: String): Boolean { + val accessType = getAccessTypeFromNative(nativeAccessType) ?: return false + return when (accessType) { + ACCESS_RESOURCES -> assetsDirAccess.remove(filename) + ACCESS_FILESYSTEM -> fileSystemDirAccess.remove(filename) + } + } + +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/directory/FilesystemDirectoryAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/directory/FilesystemDirectoryAccess.kt new file mode 100644 index 0000000000..54fc56fa3e --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/directory/FilesystemDirectoryAccess.kt @@ -0,0 +1,231 @@ +/*************************************************************************/ +/* FileSystemDirectoryAccess.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io.directory + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Build +import android.os.storage.StorageManager +import android.util.Log +import android.util.SparseArray +import org.godotengine.godot.io.StorageScope +import org.godotengine.godot.io.directory.DirectoryAccessHandler.Companion.INVALID_DIR_ID +import org.godotengine.godot.io.directory.DirectoryAccessHandler.Companion.STARTING_DIR_ID +import org.godotengine.godot.io.file.FileAccessHandler +import java.io.File + +/** + * Handles directories access with the internal and external filesystem. + */ +internal class FilesystemDirectoryAccess(private val context: Context): + DirectoryAccessHandler.DirectoryAccess { + + companion object { + private val TAG = FilesystemDirectoryAccess::class.java.simpleName + } + + private data class DirData(val dirFile: File, val files: Array<File>, var current: Int = 0) + + private val storageScopeIdentifier = StorageScope.Identifier(context) + private val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager + private var lastDirId = STARTING_DIR_ID + private val dirs = SparseArray<DirData>() + + private fun inScope(path: String): Boolean { + // Directory access is available for shared storage on Android 11+ + // On Android 10, access is also available as long as the `requestLegacyExternalStorage` + // tag is available. + return storageScopeIdentifier.identifyStorageScope(path) != StorageScope.UNKNOWN + } + + override fun hasDirId(dirId: Int) = dirs.indexOfKey(dirId) >= 0 + + override fun dirOpen(path: String): Int { + if (!inScope(path)) { + Log.w(TAG, "Path $path is not accessible.") + return INVALID_DIR_ID + } + + // Check this is a directory. + val dirFile = File(path) + if (!dirFile.isDirectory) { + return INVALID_DIR_ID + } + + // Get the files in the directory + val files = dirFile.listFiles()?: return INVALID_DIR_ID + + // Create the data representing this directory + val dirData = DirData(dirFile, files) + + dirs.put(++lastDirId, dirData) + return lastDirId + } + + override fun dirExists(path: String): Boolean { + if (!inScope(path)) { + Log.w(TAG, "Path $path is not accessible.") + return false + } + + try { + return File(path).isDirectory + } catch (e: SecurityException) { + return false + } + } + + override fun fileExists(path: String) = FileAccessHandler.fileExists(context, storageScopeIdentifier, path) + + override fun dirNext(dirId: Int): String { + val dirData = dirs[dirId] + if (dirData.current >= dirData.files.size) { + dirData.current++ + return "" + } + + return dirData.files[dirData.current++].name + } + + override fun dirClose(dirId: Int) { + dirs.remove(dirId) + } + + override fun dirIsDir(dirId: Int): Boolean { + val dirData = dirs[dirId] + + var index = dirData.current + if (index > 0) { + index-- + } + + if (index >= dirData.files.size) { + return false + } + + return dirData.files[index].isDirectory + } + + override fun isCurrentHidden(dirId: Int): Boolean { + val dirData = dirs[dirId] + + var index = dirData.current + if (index > 0) { + index-- + } + + if (index >= dirData.files.size) { + return false + } + + return dirData.files[index].isHidden + } + + override fun getDriveCount(): Int { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + storageManager.storageVolumes.size + } else { + 0 + } + } + + override fun getDrive(drive: Int): String { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + return "" + } + + if (drive < 0 || drive >= storageManager.storageVolumes.size) { + return "" + } + + val storageVolume = storageManager.storageVolumes[drive] + return storageVolume.getDescription(context) + } + + override fun makeDir(dir: String): Boolean { + if (!inScope(dir)) { + Log.w(TAG, "Directory $dir is not accessible.") + return false + } + + try { + val dirFile = File(dir) + return dirFile.isDirectory || dirFile.mkdirs() + } catch (e: SecurityException) { + return false + } + } + + @SuppressLint("UsableSpace") + override fun getSpaceLeft() = context.getExternalFilesDir(null)?.usableSpace ?: 0L + + override fun rename(from: String, to: String): Boolean { + if (!inScope(from) || !inScope(to)) { + Log.w(TAG, "Argument filenames are not accessible:\n" + + "from: $from\n" + + "to: $to") + return false + } + + return try { + val fromFile = File(from) + if (fromFile.isDirectory) { + fromFile.renameTo(File(to)) + } else { + FileAccessHandler.renameFile(context, storageScopeIdentifier, from, to) + } + } catch (e: SecurityException) { + false + } + } + + override fun remove(filename: String): Boolean { + if (!inScope(filename)) { + Log.w(TAG, "Filename $filename is not accessible.") + return false + } + + return try { + val deleteFile = File(filename) + if (deleteFile.exists()) { + if (deleteFile.isDirectory) { + deleteFile.delete() + } else { + FileAccessHandler.removeFile(context, storageScopeIdentifier, filename) + } + } else { + true + } + } catch (e: SecurityException) { + false + } + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt new file mode 100644 index 0000000000..463dabfb23 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt @@ -0,0 +1,187 @@ +/*************************************************************************/ +/* DataAccess.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io.file + +import android.content.Context +import android.os.Build +import android.util.Log +import org.godotengine.godot.io.StorageScope +import java.io.IOException +import java.nio.ByteBuffer +import java.nio.channels.FileChannel +import kotlin.math.max + +/** + * Base class for file IO operations. + * + * Its derived instances provide concrete implementations to handle regular file access, as well + * as file access through the media store API on versions of Android were scoped storage is enabled. + */ +internal abstract class DataAccess(private val filePath: String) { + + companion object { + private val TAG = DataAccess::class.java.simpleName + + fun generateDataAccess( + storageScope: StorageScope, + context: Context, + filePath: String, + accessFlag: FileAccessFlags + ): DataAccess? { + return when (storageScope) { + StorageScope.APP -> FileData(filePath, accessFlag) + + StorageScope.SHARED -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + MediaStoreData(context, filePath, accessFlag) + } else { + null + } + + StorageScope.UNKNOWN -> null + } + } + + fun fileExists(storageScope: StorageScope, context: Context, path: String): Boolean { + return when(storageScope) { + StorageScope.APP -> FileData.fileExists(path) + StorageScope.SHARED -> MediaStoreData.fileExists(context, path) + StorageScope.UNKNOWN -> false + } + } + + fun fileLastModified(storageScope: StorageScope, context: Context, path: String): Long { + return when(storageScope) { + StorageScope.APP -> FileData.fileLastModified(path) + StorageScope.SHARED -> MediaStoreData.fileLastModified(context, path) + StorageScope.UNKNOWN -> 0L + } + } + + fun removeFile(storageScope: StorageScope, context: Context, path: String): Boolean { + return when(storageScope) { + StorageScope.APP -> FileData.delete(path) + StorageScope.SHARED -> MediaStoreData.delete(context, path) + StorageScope.UNKNOWN -> false + } + } + + fun renameFile(storageScope: StorageScope, context: Context, from: String, to: String): Boolean { + return when(storageScope) { + StorageScope.APP -> FileData.rename(from, to) + StorageScope.SHARED -> MediaStoreData.rename(context, from, to) + StorageScope.UNKNOWN -> false + } + } + } + + protected abstract val fileChannel: FileChannel + internal var endOfFile = false + private set + + fun close() { + try { + fileChannel.close() + } catch (e: IOException) { + Log.w(TAG, "Exception when closing file $filePath.", e) + } + } + + fun flush() { + try { + fileChannel.force(false) + } catch (e: IOException) { + Log.w(TAG, "Exception when flushing file $filePath.", e) + } + } + + fun seek(position: Long) { + try { + fileChannel.position(position) + if (position <= size()) { + endOfFile = false + } + } catch (e: Exception) { + Log.w(TAG, "Exception when seeking file $filePath.", e) + } + } + + fun seekFromEnd(positionFromEnd: Long) { + val positionFromBeginning = max(0, size() - positionFromEnd) + seek(positionFromBeginning) + } + + fun position(): Long { + return try { + fileChannel.position() + } catch (e: IOException) { + Log.w( + TAG, + "Exception when retrieving position for file $filePath.", + e + ) + 0L + } + } + + fun size() = try { + fileChannel.size() + } catch (e: IOException) { + Log.w(TAG, "Exception when retrieving size for file $filePath.", e) + 0L + } + + fun read(buffer: ByteBuffer): Int { + return try { + val readBytes = fileChannel.read(buffer) + endOfFile = readBytes == -1 + || (fileChannel.position() >= fileChannel.size() && fileChannel.size() > 0) + if (readBytes == -1) { + 0 + } else { + readBytes + } + } catch (e: IOException) { + Log.w(TAG, "Exception while reading from file $filePath.", e) + 0 + } + } + + fun write(buffer: ByteBuffer) { + try { + val writtenBytes = fileChannel.write(buffer) + if (writtenBytes > 0) { + endOfFile = false + } + } catch (e: IOException) { + Log.w(TAG, "Exception while writing to file $filePath.", e) + } + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessFlags.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessFlags.kt new file mode 100644 index 0000000000..c6b242a4b6 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessFlags.kt @@ -0,0 +1,87 @@ +/*************************************************************************/ +/* FileAccessFlags.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io.file + +/** + * Android representation of Godot native access flags. + */ +internal enum class FileAccessFlags(val nativeValue: Int) { + /** + * Opens the file for read operations. + * The cursor is positioned at the beginning of the file. + */ + READ(1), + + /** + * Opens the file for write operations. + * The file is created if it does not exist, and truncated if it does. + */ + WRITE(2), + + /** + * Opens the file for read and write operations. + * Does not truncate the file. The cursor is positioned at the beginning of the file. + */ + READ_WRITE(3), + + /** + * Opens the file for read and write operations. + * The file is created if it does not exist, and truncated if it does. + * The cursor is positioned at the beginning of the file. + */ + WRITE_READ(7); + + fun getMode(): String { + return when (this) { + READ -> "r" + WRITE -> "w" + READ_WRITE, WRITE_READ -> "rw" + } + } + + fun shouldTruncate(): Boolean { + return when (this) { + READ, READ_WRITE -> false + WRITE, WRITE_READ -> true + } + } + + companion object { + fun fromNativeModeFlags(modeFlag: Int): FileAccessFlags? { + for (flag in values()) { + if (flag.nativeValue == modeFlag) { + return flag + } + } + return null + } + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt new file mode 100644 index 0000000000..04b6772c45 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt @@ -0,0 +1,203 @@ +/*************************************************************************/ +/* FileAccessHandler.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io.file + +import android.content.Context +import android.util.Log +import android.util.SparseArray +import org.godotengine.godot.io.StorageScope +import java.io.FileNotFoundException +import java.nio.ByteBuffer + +/** + * Handles regular and media store file access and interactions. + */ +class FileAccessHandler(val context: Context) { + + companion object { + private val TAG = FileAccessHandler::class.java.simpleName + + private const val FILE_NOT_FOUND_ERROR_ID = -1 + private const val INVALID_FILE_ID = 0 + private const val STARTING_FILE_ID = 1 + + internal fun fileExists(context: Context, storageScopeIdentifier: StorageScope.Identifier, path: String?): Boolean { + val storageScope = storageScopeIdentifier.identifyStorageScope(path) + if (storageScope == StorageScope.UNKNOWN) { + return false + } + + return try { + DataAccess.fileExists(storageScope, context, path!!) + } catch (e: SecurityException) { + false + } + } + + internal fun removeFile(context: Context, storageScopeIdentifier: StorageScope.Identifier, path: String?): Boolean { + val storageScope = storageScopeIdentifier.identifyStorageScope(path) + if (storageScope == StorageScope.UNKNOWN) { + return false + } + + return try { + DataAccess.removeFile(storageScope, context, path!!) + } catch (e: Exception) { + false + } + } + + internal fun renameFile(context: Context, storageScopeIdentifier: StorageScope.Identifier, from: String?, to: String?): Boolean { + val storageScope = storageScopeIdentifier.identifyStorageScope(from) + if (storageScope == StorageScope.UNKNOWN) { + return false + } + + return try { + DataAccess.renameFile(storageScope, context, from!!, to!!) + } catch (e: Exception) { + false + } + } + } + + private val storageScopeIdentifier = StorageScope.Identifier(context) + private val files = SparseArray<DataAccess>() + private var lastFileId = STARTING_FILE_ID + + private fun hasFileId(fileId: Int) = files.indexOfKey(fileId) >= 0 + + fun fileOpen(path: String?, modeFlags: Int): Int { + val storageScope = storageScopeIdentifier.identifyStorageScope(path) + if (storageScope == StorageScope.UNKNOWN) { + return INVALID_FILE_ID + } + + try { + val accessFlag = FileAccessFlags.fromNativeModeFlags(modeFlags) ?: return INVALID_FILE_ID + val dataAccess = DataAccess.generateDataAccess(storageScope, context, path!!, accessFlag) ?: return INVALID_FILE_ID + + files.put(++lastFileId, dataAccess) + return lastFileId + } catch (e: FileNotFoundException) { + return FILE_NOT_FOUND_ERROR_ID + } catch (e: Exception) { + Log.w(TAG, "Error while opening $path", e) + return INVALID_FILE_ID + } + } + + fun fileGetSize(fileId: Int): Long { + if (!hasFileId(fileId)) { + return 0L + } + + return files[fileId].size() + } + + fun fileSeek(fileId: Int, position: Long) { + if (!hasFileId(fileId)) { + return + } + + files[fileId].seek(position) + } + + fun fileSeekFromEnd(fileId: Int, position: Long) { + if (!hasFileId(fileId)) { + return + } + + files[fileId].seekFromEnd(position) + } + + fun fileRead(fileId: Int, byteBuffer: ByteBuffer?): Int { + if (!hasFileId(fileId) || byteBuffer == null) { + return 0 + } + + return files[fileId].read(byteBuffer) + } + + fun fileWrite(fileId: Int, byteBuffer: ByteBuffer?) { + if (!hasFileId(fileId) || byteBuffer == null) { + return + } + + files[fileId].write(byteBuffer) + } + + fun fileFlush(fileId: Int) { + if (!hasFileId(fileId)) { + return + } + + files[fileId].flush() + } + + fun fileExists(path: String?) = Companion.fileExists(context, storageScopeIdentifier, path) + + fun fileLastModified(filepath: String?): Long { + val storageScope = storageScopeIdentifier.identifyStorageScope(filepath) + if (storageScope == StorageScope.UNKNOWN) { + return 0L + } + + return try { + DataAccess.fileLastModified(storageScope, context, filepath!!) + } catch (e: SecurityException) { + 0L + } + } + + fun fileGetPosition(fileId: Int): Long { + if (!hasFileId(fileId)) { + return 0L + } + + return files[fileId].position() + } + + fun isFileEof(fileId: Int): Boolean { + if (!hasFileId(fileId)) { + return false + } + + return files[fileId].endOfFile + } + + fun fileClose(fileId: Int) { + if (hasFileId(fileId)) { + files[fileId].close() + files.remove(fileId) + } + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileData.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileData.kt new file mode 100644 index 0000000000..5af694ad99 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileData.kt @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* FileData.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io.file + +import java.io.File +import java.io.FileOutputStream +import java.io.RandomAccessFile +import java.nio.channels.FileChannel + +/** + * Implementation of [DataAccess] which handles regular (not scoped) file access and interactions. + */ +internal class FileData(filePath: String, accessFlag: FileAccessFlags) : DataAccess(filePath) { + + companion object { + private val TAG = FileData::class.java.simpleName + + fun fileExists(path: String): Boolean { + return try { + File(path).isFile + } catch (e: SecurityException) { + false + } + } + + fun fileLastModified(filepath: String): Long { + return try { + File(filepath).lastModified() + } catch (e: SecurityException) { + 0L + } + } + + fun delete(filepath: String): Boolean { + return try { + File(filepath).delete() + } catch (e: Exception) { + false + } + } + + fun rename(from: String, to: String): Boolean { + return try { + val fromFile = File(from) + fromFile.renameTo(File(to)) + } catch (e: Exception) { + false + } + } + } + + override val fileChannel: FileChannel + + init { + if (accessFlag == FileAccessFlags.WRITE) { + fileChannel = FileOutputStream(filePath, !accessFlag.shouldTruncate()).channel + } else { + fileChannel = RandomAccessFile(filePath, accessFlag.getMode()).channel + } + + if (accessFlag.shouldTruncate()) { + fileChannel.truncate(0) + } + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/MediaStoreData.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/MediaStoreData.kt new file mode 100644 index 0000000000..81a7dd1705 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/MediaStoreData.kt @@ -0,0 +1,284 @@ +/*************************************************************************/ +/* MediaStoreData.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.io.file + +import android.content.ContentUris +import android.content.ContentValues +import android.content.Context +import android.database.Cursor +import android.net.Uri +import android.os.Build +import android.os.Environment +import android.provider.MediaStore +import androidx.annotation.RequiresApi + +import java.io.File +import java.io.FileInputStream +import java.io.FileNotFoundException +import java.io.FileOutputStream +import java.nio.channels.FileChannel + +/** + * Implementation of [DataAccess] which handles access and interactions with file and data + * under scoped storage via the MediaStore API. + */ +@RequiresApi(Build.VERSION_CODES.Q) +internal class MediaStoreData(context: Context, filePath: String, accessFlag: FileAccessFlags) : + DataAccess(filePath) { + + private data class DataItem( + val id: Long, + val uri: Uri, + val displayName: String, + val relativePath: String, + val size: Int, + val dateModified: Int, + val mediaType: Int + ) + + companion object { + private val TAG = MediaStoreData::class.java.simpleName + + private val COLLECTION = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) + + private val PROJECTION = arrayOf( + MediaStore.Files.FileColumns._ID, + MediaStore.Files.FileColumns.DISPLAY_NAME, + MediaStore.Files.FileColumns.RELATIVE_PATH, + MediaStore.Files.FileColumns.SIZE, + MediaStore.Files.FileColumns.DATE_MODIFIED, + MediaStore.Files.FileColumns.MEDIA_TYPE, + ) + + private const val SELECTION_BY_PATH = "${MediaStore.Files.FileColumns.DISPLAY_NAME} = ? " + + " AND ${MediaStore.Files.FileColumns.RELATIVE_PATH} = ?" + + private fun getSelectionByPathArguments(path: String): Array<String> { + return arrayOf(getMediaStoreDisplayName(path), getMediaStoreRelativePath(path)) + } + + private const val SELECTION_BY_ID = "${MediaStore.Files.FileColumns._ID} = ? " + + private fun getSelectionByIdArgument(id: Long) = arrayOf(id.toString()) + + private fun getMediaStoreDisplayName(path: String) = File(path).name + + private fun getMediaStoreRelativePath(path: String): String { + val pathFile = File(path) + val environmentDir = Environment.getExternalStorageDirectory() + var relativePath = (pathFile.parent?.replace(environmentDir.absolutePath, "") ?: "").trim('/') + if (relativePath.isNotBlank()) { + relativePath += "/" + } + return relativePath + } + + private fun queryById(context: Context, id: Long): List<DataItem> { + val query = context.contentResolver.query( + COLLECTION, + PROJECTION, + SELECTION_BY_ID, + getSelectionByIdArgument(id), + null + ) + return dataItemFromCursor(query) + } + + private fun queryByPath(context: Context, path: String): List<DataItem> { + val query = context.contentResolver.query( + COLLECTION, + PROJECTION, + SELECTION_BY_PATH, + getSelectionByPathArguments(path), + null + ) + return dataItemFromCursor(query) + } + + private fun dataItemFromCursor(query: Cursor?): List<DataItem> { + query?.use { cursor -> + cursor.count + if (cursor.count == 0) { + return emptyList() + } + val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID) + val displayNameColumn = + cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME) + val relativePathColumn = + cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.RELATIVE_PATH) + val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.SIZE) + val dateModifiedColumn = + cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATE_MODIFIED) + val mediaTypeColumn = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MEDIA_TYPE) + + val result = ArrayList<DataItem>() + while (cursor.moveToNext()) { + val id = cursor.getLong(idColumn) + result.add( + DataItem( + id, + ContentUris.withAppendedId(COLLECTION, id), + cursor.getString(displayNameColumn), + cursor.getString(relativePathColumn), + cursor.getInt(sizeColumn), + cursor.getInt(dateModifiedColumn), + cursor.getInt(mediaTypeColumn) + ) + ) + } + return result + } + return emptyList() + } + + private fun addFile(context: Context, path: String): DataItem? { + val fileDetails = ContentValues().apply { + put(MediaStore.Files.FileColumns._ID, 0) + put(MediaStore.Files.FileColumns.DISPLAY_NAME, getMediaStoreDisplayName(path)) + put(MediaStore.Files.FileColumns.RELATIVE_PATH, getMediaStoreRelativePath(path)) + } + + context.contentResolver.insert(COLLECTION, fileDetails) ?: return null + + // File was successfully added, let's retrieve its info + val infos = queryByPath(context, path) + if (infos.isEmpty()) { + return null + } + + return infos[0] + } + + fun delete(context: Context, path: String): Boolean { + val itemsToDelete = queryByPath(context, path) + if (itemsToDelete.isEmpty()) { + return false + } + + val resolver = context.contentResolver + var itemsDeleted = 0 + for (item in itemsToDelete) { + itemsDeleted += resolver.delete(item.uri, null, null) + } + + return itemsDeleted > 0 + } + + fun fileExists(context: Context, path: String): Boolean { + return queryByPath(context, path).isNotEmpty() + } + + fun fileLastModified(context: Context, path: String): Long { + val result = queryByPath(context, path) + if (result.isEmpty()) { + return 0L + } + + val dataItem = result[0] + return dataItem.dateModified.toLong() + } + + fun rename(context: Context, from: String, to: String): Boolean { + // Ensure the source exists. + val sources = queryByPath(context, from) + if (sources.isEmpty()) { + return false + } + + // Take the first source + val source = sources[0] + + // Set up the updated values + val updatedDetails = ContentValues().apply { + put(MediaStore.Files.FileColumns.DISPLAY_NAME, getMediaStoreDisplayName(to)) + put(MediaStore.Files.FileColumns.RELATIVE_PATH, getMediaStoreRelativePath(to)) + } + + val updated = context.contentResolver.update( + source.uri, + updatedDetails, + SELECTION_BY_ID, + getSelectionByIdArgument(source.id) + ) + return updated > 0 + } + } + + private val id: Long + private val uri: Uri + override val fileChannel: FileChannel + + init { + val contentResolver = context.contentResolver + val dataItems = queryByPath(context, filePath) + + val dataItem = when (accessFlag) { + FileAccessFlags.READ -> { + // The file should already exist + if (dataItems.isEmpty()) { + throw FileNotFoundException("Unable to access file $filePath") + } + + val dataItem = dataItems[0] + dataItem + } + + FileAccessFlags.WRITE, FileAccessFlags.READ_WRITE, FileAccessFlags.WRITE_READ -> { + // Create the file if it doesn't exist + val dataItem = if (dataItems.isEmpty()) { + addFile(context, filePath) + } else { + dataItems[0] + } + + if (dataItem == null) { + throw FileNotFoundException("Unable to access file $filePath") + } + dataItem + } + } + + id = dataItem.id + uri = dataItem.uri + + val parcelFileDescriptor = contentResolver.openFileDescriptor(uri, accessFlag.getMode()) + ?: throw IllegalStateException("Unable to access file descriptor") + fileChannel = if (accessFlag == FileAccessFlags.READ) { + FileInputStream(parcelFileDescriptor.fileDescriptor).channel + } else { + FileOutputStream(parcelFileDescriptor.fileDescriptor).channel + } + + if (accessFlag.shouldTruncate()) { + fileChannel.truncate(0) + } + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java index e5b4f41153..57db0709f0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java @@ -32,10 +32,14 @@ package org.godotengine.godot.utils; import android.Manifest; import android.app.Activity; +import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; +import android.net.Uri; import android.os.Build; +import android.os.Environment; +import android.provider.Settings; import android.util.Log; import androidx.core.content.ContextCompat; @@ -53,7 +57,8 @@ public final class PermissionsUtil { static final int REQUEST_RECORD_AUDIO_PERMISSION = 1; static final int REQUEST_CAMERA_PERMISSION = 2; static final int REQUEST_VIBRATE_PERMISSION = 3; - static final int REQUEST_ALL_PERMISSION_REQ_CODE = 1001; + public static final int REQUEST_ALL_PERMISSION_REQ_CODE = 1001; + public static final int REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE = 2002; private PermissionsUtil() { } @@ -108,13 +113,26 @@ public final class PermissionsUtil { if (manifestPermissions.length == 0) return true; - List<String> dangerousPermissions = new ArrayList<>(); + List<String> requestedPermissions = new ArrayList<>(); for (String manifestPermission : manifestPermissions) { try { - PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission); - int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel; - if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) != PackageManager.PERMISSION_GRANTED) { - dangerousPermissions.add(manifestPermission); + if (manifestPermission.equals(Manifest.permission.MANAGE_EXTERNAL_STORAGE)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { + try { + Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); + intent.setData(Uri.parse(String.format("package:%s", activity.getPackageName()))); + activity.startActivityForResult(intent, REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE); + } catch (Exception ignored) { + Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); + activity.startActivityForResult(intent, REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE); + } + } + } else { + PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission); + int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel; + if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) != PackageManager.PERMISSION_GRANTED) { + requestedPermissions.add(manifestPermission); + } } } catch (PackageManager.NameNotFoundException e) { // Skip this permission and continue. @@ -122,13 +140,12 @@ public final class PermissionsUtil { } } - if (dangerousPermissions.isEmpty()) { + if (requestedPermissions.isEmpty()) { // If list is empty, all of dangerous permissions were granted. return true; } - String[] requestedPermissions = dangerousPermissions.toArray(new String[0]); - activity.requestPermissions(requestedPermissions, REQUEST_ALL_PERMISSION_REQ_CODE); + activity.requestPermissions(requestedPermissions.toArray(new String[0]), REQUEST_ALL_PERMISSION_REQ_CODE); return false; } @@ -148,13 +165,19 @@ public final class PermissionsUtil { if (manifestPermissions.length == 0) return manifestPermissions; - List<String> dangerousPermissions = new ArrayList<>(); + List<String> grantedPermissions = new ArrayList<>(); for (String manifestPermission : manifestPermissions) { try { - PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission); - int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel; - if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) == PackageManager.PERMISSION_GRANTED) { - dangerousPermissions.add(manifestPermission); + if (manifestPermission.equals(Manifest.permission.MANAGE_EXTERNAL_STORAGE)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && Environment.isExternalStorageManager()) { + grantedPermissions.add(manifestPermission); + } + } else { + PermissionInfo permissionInfo = getPermissionInfo(activity, manifestPermission); + int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel; + if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, manifestPermission) == PackageManager.PERMISSION_GRANTED) { + grantedPermissions.add(manifestPermission); + } } } catch (PackageManager.NameNotFoundException e) { // Skip this permission and continue. @@ -162,7 +185,7 @@ public final class PermissionsUtil { } } - return dangerousPermissions.toArray(new String[0]); + return grantedPermissions.toArray(new String[0]); } /** @@ -177,7 +200,7 @@ public final class PermissionsUtil { if (permission.equals(p)) return true; } - } catch (PackageManager.NameNotFoundException e) { + } catch (PackageManager.NameNotFoundException ignored) { } return false; diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index de666f1b11..f4de4acfad 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -43,6 +43,7 @@ #include "dir_access_jandroid.h" #include "display_server_android.h" #include "file_access_android.h" +#include "file_access_filesystem_jandroid.h" #include "jni_utils.h" #include "main/main.h" #include "net_socket_android.h" @@ -78,13 +79,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHei } } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject activity, jobject godot_instance, jobject p_asset_manager, jboolean p_use_apk_expansion) { +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion, jobject p_godot_tts) { JavaVM *jvm; env->GetJavaVM(&jvm); // create our wrapper classes - godot_java = new GodotJavaWrapper(env, activity, godot_instance); - godot_io_java = new GodotIOJavaWrapper(env, godot_java->get_member_object("io", "Lorg/godotengine/godot/GodotIO;", env)); + godot_java = new GodotJavaWrapper(env, p_activity, p_godot_instance); + godot_io_java = new GodotIOJavaWrapper(env, p_godot_io); init_thread_jandroid(jvm, env); @@ -92,9 +93,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr); - DirAccessJAndroid::setup(godot_io_java->get_instance()); - NetSocketAndroid::setup(godot_java->get_member_object("netUtils", "Lorg/godotengine/godot/utils/GodotNetUtils;", env)); - TTS_Android::setup(godot_java->get_member_object("tts", "Lorg/godotengine/godot/tts/GodotTTS;", env)); + DirAccessJAndroid::setup(p_directory_access_handler); + FileAccessFilesystemJAndroid::setup(p_file_access_handler); + NetSocketAndroid::setup(p_net_utils); + TTS_Android::setup(p_godot_tts); os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion); @@ -157,6 +159,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc memfree(cmdline); } + // Note: --help and --version return ERR_HELP, but this should be translated to 0 if exit codes are propagated. if (err != OK) { return; // should exit instead and print the error } @@ -306,15 +309,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env } // Called on the UI thread -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) { - if (step.get() <= 0) { - return; - } - - input_handler->process_scroll(Point2(p_x, p_y)); -} - -// Called on the UI thread JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) { if (step.get() <= 0) { return; diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index e1d30eea77..de16f197b8 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -37,7 +37,7 @@ // These functions can be called from within JAVA and are the means by which our JAVA implementation calls back into our C++ code. // See java/src/org/godotengine/godot/GodotLib.java for the JAVA side of this (yes that's why we have the long names) extern "C" { -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject activity, jobject godot_instance, jobject p_asset_manager, jboolean p_use_apk_expansion); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion, jobject p_godot_tts); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jobject p_surface, jint p_width, jint p_height); @@ -51,7 +51,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEn JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value); diff --git a/platform/android/java_godot_view_wrapper.h b/platform/android/java_godot_view_wrapper.h index b1f258bbb5..c52f459d64 100644 --- a/platform/android/java_godot_view_wrapper.h +++ b/platform/android/java_godot_view_wrapper.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_JAVA_GODOT_VIEW_WRAPPER_H -#define GODOT_JAVA_GODOT_VIEW_WRAPPER_H +#ifndef JAVA_GODOT_VIEW_WRAPPER_H +#define JAVA_GODOT_VIEW_WRAPPER_H #include <android/log.h> #include <jni.h> @@ -57,4 +57,4 @@ public: ~GodotJavaViewWrapper(); }; -#endif // GODOT_JAVA_GODOT_VIEW_WRAPPER_H +#endif // JAVA_GODOT_VIEW_WRAPPER_H diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 6674428de8..0f551e7f4f 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -40,6 +40,7 @@ #include "dir_access_jandroid.h" #include "file_access_android.h" +#include "file_access_filesystem_jandroid.h" #include "net_socket_android.h" #include <dlfcn.h> @@ -93,7 +94,7 @@ void OS_Android::initialize_core() { } #endif FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); - FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM); + FileAccess::make_default<FileAccessFilesystemJAndroid>(FileAccess::ACCESS_FILESYSTEM); #ifdef TOOLS_ENABLED DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES); @@ -105,7 +106,7 @@ void OS_Android::initialize_core() { } #endif DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA); - DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM); + DirAccess::make_default<DirAccessJAndroid>(DirAccess::ACCESS_FILESYSTEM); NetSocketAndroid::make_default(); } @@ -300,6 +301,33 @@ String OS_Android::get_system_dir(SystemDir p_dir, bool p_shared_storage) const return godot_io_java->get_system_dir(p_dir, p_shared_storage); } +Error OS_Android::move_to_trash(const String &p_path) { + Ref<DirAccess> da_ref = DirAccess::create_for_path(p_path); + if (da_ref.is_null()) { + return FAILED; + } + + // Check if it's a directory + if (da_ref->dir_exists(p_path)) { + Error err = da_ref->change_dir(p_path); + if (err) { + return err; + } + // This is directory, let's erase its contents + err = da_ref->erase_contents_recursive(); + if (err) { + return err; + } + // Remove the top directory + return da_ref->remove(p_path); + } else if (da_ref->file_exists(p_path)) { + // This is a file, let's remove it. + return da_ref->remove(p_path); + } else { + return FAILED; + } +} + void OS_Android::set_display_size(const Size2i &p_size) { display_size = p_size; } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 3f607eac48..96c06d715c 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -122,6 +122,8 @@ public: virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override; + virtual Error move_to_trash(const String &p_path) override; + void vibrate_handheld(int p_duration_ms) override; virtual String get_config_path() const override; diff --git a/platform/iphone/SCsub b/platform/ios/SCsub index 5e10bf5646..bf12ab6dd7 100644 --- a/platform/iphone/SCsub +++ b/platform/ios/SCsub @@ -2,16 +2,16 @@ Import("env") -iphone_lib = [ - "godot_iphone.mm", - "os_iphone.mm", +ios_lib = [ + "godot_ios.mm", + "os_ios.mm", "main.m", "app_delegate.mm", "view_controller.mm", "ios.mm", - "vulkan_context_iphone.mm", - "display_server_iphone.mm", - "joypad_iphone.mm", + "vulkan_context_ios.mm", + "display_server_ios.mm", + "joypad_ios.mm", "godot_view.mm", "tts_ios.mm", "display_layer.mm", @@ -23,7 +23,7 @@ iphone_lib = [ ] env_ios = env.Clone() -ios_lib = env_ios.add_library("iphone", iphone_lib) +ios_lib = env_ios.add_library("ios", ios_lib) # (iOS) Enable module support env_ios.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) @@ -32,9 +32,9 @@ env_ios.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) def combine_libs(target=None, source=None, env=None): lib_path = target[0].srcnode().abspath if "osxcross" in env: - libtool = "$IPHONEPATH/usr/bin/${ios_triple}libtool" + libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}libtool" else: - libtool = "$IPHONEPATH/usr/bin/libtool" + libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/libtool" env.Execute( libtool + ' -static -o "' + lib_path + '" ' + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source]) ) diff --git a/platform/iphone/api/api.cpp b/platform/ios/api/api.cpp index f2e6fd7a7a..00c76a9256 100644 --- a/platform/iphone/api/api.cpp +++ b/platform/ios/api/api.cpp @@ -30,19 +30,19 @@ #include "api.h" -#if defined(IPHONE_ENABLED) +#if defined(IOS_ENABLED) -void register_iphone_api() { +void register_ios_api() { godot_ios_plugins_initialize(); } -void unregister_iphone_api() { +void unregister_ios_api() { godot_ios_plugins_deinitialize(); } #else -void register_iphone_api() {} -void unregister_iphone_api() {} +void register_ios_api() {} +void unregister_ios_api() {} #endif diff --git a/platform/iphone/api/api.h b/platform/ios/api/api.h index ece91a9f1a..c7fd4ce77b 100644 --- a/platform/iphone/api/api.h +++ b/platform/ios/api/api.h @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IPHONE_API_H -#define IPHONE_API_H +#ifndef IOS_API_H +#define IOS_API_H -#if defined(IPHONE_ENABLED) +#if defined(IOS_ENABLED) extern void godot_ios_plugins_initialize(); extern void godot_ios_plugins_deinitialize(); #endif -void register_iphone_api(); -void unregister_iphone_api(); +void register_ios_api(); +void unregister_ios_api(); -#endif // IPHONE_API_H +#endif // IOS_API_H diff --git a/platform/iphone/app_delegate.h b/platform/ios/app_delegate.h index 0ec1dc071b..0ec1dc071b 100644 --- a/platform/iphone/app_delegate.h +++ b/platform/ios/app_delegate.h diff --git a/platform/iphone/app_delegate.mm b/platform/ios/app_delegate.mm index c5c9b5a5f9..fb183d52d4 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/ios/app_delegate.mm @@ -34,7 +34,7 @@ #include "drivers/coreaudio/audio_driver_coreaudio.h" #import "godot_view.h" #include "main/main.h" -#include "os_iphone.h" +#include "os_ios.h" #import "view_controller.h" #import <AVFoundation/AVFoundation.h> @@ -45,8 +45,8 @@ extern int gargc; extern char **gargv; -extern int iphone_main(int, char **, String, String); -extern void iphone_finish(); +extern int ios_main(int, char **, String, String); +extern void ios_finish(); @implementation AppDelegate @@ -71,7 +71,7 @@ static ViewController *mainViewController = nil; paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cacheDirectory = [paths objectAtIndex:0]; - int err = iphone_main(gargc, gargv, String::utf8([documentsDirectory UTF8String]), String::utf8([cacheDirectory UTF8String])); + int err = ios_main(gargc, gargv, String::utf8([documentsDirectory UTF8String]), String::utf8([cacheDirectory UTF8String])); if (err != 0) { // bail, things did not go very well for us, should probably output a message on screen with our error code... @@ -106,10 +106,10 @@ static ViewController *mainViewController = nil; if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) { if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) { NSLog(@"Audio interruption began"); - OSIPhone::get_singleton()->on_focus_out(); + OS_IOS::get_singleton()->on_focus_out(); } else if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]) { NSLog(@"Audio interruption ended"); - OSIPhone::get_singleton()->on_focus_in(); + OS_IOS::get_singleton()->on_focus_in(); } } } @@ -121,7 +121,7 @@ static ViewController *mainViewController = nil; } - (void)applicationWillTerminate:(UIApplication *)application { - iphone_finish(); + ios_finish(); } // When application goes to background (e.g. user switches to another app or presses Home), @@ -135,11 +135,11 @@ static ViewController *mainViewController = nil; // notification panel by swiping from the upper part of the screen. - (void)applicationWillResignActive:(UIApplication *)application { - OSIPhone::get_singleton()->on_focus_out(); + OS_IOS::get_singleton()->on_focus_out(); } - (void)applicationDidBecomeActive:(UIApplication *)application { - OSIPhone::get_singleton()->on_focus_in(); + OS_IOS::get_singleton()->on_focus_in(); } - (void)dealloc { diff --git a/platform/iphone/detect.py b/platform/ios/detect.py index 392a0151be..67c90b10a0 100644 --- a/platform/iphone/detect.py +++ b/platform/ios/detect.py @@ -23,11 +23,11 @@ def get_opts(): return [ ( - "IPHONEPATH", - "Path to iPhone toolchain", + "IOS_TOOLCHAIN_PATH", + "Path to iOS toolchain", "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain", ), - ("IPHONESDK", "Path to the iPhone SDK", ""), + ("IOS_SDK_PATH", "Path to the iOS SDK", ""), BoolVariable("ios_simulator", "Build for iOS Simulator", False), BoolVariable("ios_exceptions", "Enable exceptions", False), ("ios_triple", "Triple for ios toolchain", ""), @@ -75,10 +75,10 @@ def configure(env): if "OSXCROSS_IOS" in os.environ: env["osxcross"] = True - env["ENV"]["PATH"] = env["IPHONEPATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"] + env["ENV"]["PATH"] = env["IOS_TOOLCHAIN_PATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"] - compiler_path = "$IPHONEPATH/usr/bin/${ios_triple}" - s_compiler_path = "$IPHONEPATH/Developer/usr/bin/" + compiler_path = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}" + s_compiler_path = "$IOS_TOOLCHAIN_PATH/Developer/usr/bin/" ccache_path = os.environ.get("CCACHE") if ccache_path is None: @@ -97,11 +97,13 @@ def configure(env): ## Compile flags if env["ios_simulator"]: - detect_darwin_sdk_path("iphonesimulator", env) + detect_darwin_sdk_path("iossimulator", env) + env.Append(ASFLAGS=["-mios-simulator-version-min=13.0"]) env.Append(CCFLAGS=["-mios-simulator-version-min=13.0"]) env.extra_suffix = ".simulator" + env.extra_suffix else: - detect_darwin_sdk_path("iphone", env) + detect_darwin_sdk_path("ios", env) + env.Append(ASFLAGS=["-miphoneos-version-min=11.0"]) env.Append(CCFLAGS=["-miphoneos-version-min=11.0"]) if env["arch"] == "x86_64": @@ -110,18 +112,20 @@ def configure(env): CCFLAGS=( "-fobjc-arc -arch x86_64" " -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks" - " -fasm-blocks -isysroot $IPHONESDK" + " -fasm-blocks -isysroot $IOS_SDK_PATH" ).split() ) + env.Append(ASFLAGS=["-arch", "x86_64"]) elif env["arch"] == "arm64": env.Append( CCFLAGS=( "-fobjc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing" " -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits" " -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies" - " -isysroot $IPHONESDK".split() + " -isysroot $IOS_SDK_PATH".split() ) ) + env.Append(ASFLAGS=["-arch", "arm64"]) env.Append(CPPDEFINES=["NEED_LONG_INT"]) # Disable exceptions on non-tools (template) builds @@ -131,18 +135,18 @@ def configure(env): else: env.Append(CCFLAGS=["-fno-exceptions"]) - # Temp fix for ABS/MAX/MIN macros in iPhone SDK blocking compilation + # Temp fix for ABS/MAX/MIN macros in iOS SDK blocking compilation env.Append(CCFLAGS=["-Wno-ambiguous-macro"]) env.Prepend( CPPPATH=[ - "$IPHONESDK/usr/include", - "$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers", + "$IOS_SDK_PATH/usr/include", + "$IOS_SDK_PATH/System/Library/Frameworks/AudioUnit.framework/Headers", ] ) - env.Prepend(CPPPATH=["#platform/iphone"]) - env.Append(CPPDEFINES=["IPHONE_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"]) + env.Prepend(CPPPATH=["#platform/ios"]) + env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"]) if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) diff --git a/platform/iphone/device_metrics.h b/platform/ios/device_metrics.h index b9fb9b2fd9..b9fb9b2fd9 100644 --- a/platform/iphone/device_metrics.h +++ b/platform/ios/device_metrics.h diff --git a/platform/iphone/device_metrics.m b/platform/ios/device_metrics.m index ec4dd8130d..ec4dd8130d 100644 --- a/platform/iphone/device_metrics.m +++ b/platform/ios/device_metrics.m diff --git a/platform/iphone/display_layer.h b/platform/ios/display_layer.h index a17c75dba1..a17c75dba1 100644 --- a/platform/iphone/display_layer.h +++ b/platform/ios/display_layer.h diff --git a/platform/iphone/display_layer.mm b/platform/ios/display_layer.mm index 92e81448ac..7c83494768 100644 --- a/platform/iphone/display_layer.mm +++ b/platform/ios/display_layer.mm @@ -32,9 +32,9 @@ #include "core/config/project_settings.h" #include "core/os/keyboard.h" -#include "display_server_iphone.h" +#include "display_server_ios.h" #include "main/main.h" -#include "os_iphone.h" +#include "os_ios.h" #include "servers/audio_server.h" #import <AudioToolbox/AudioServices.h> diff --git a/platform/iphone/display_server_iphone.h b/platform/ios/display_server_ios.h index 7af222e3f8..5dd4d177ea 100644 --- a/platform/iphone/display_server_iphone.h +++ b/platform/ios/display_server_ios.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_iphone.h */ +/* display_server_ios.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef display_server_iphone_h -#define display_server_iphone_h +#ifndef DISPLAY_SERVER_IOS_H +#define DISPLAY_SERVER_IOS_H #include "core/input/input.h" #include "servers/display_server.h" @@ -38,7 +38,7 @@ #include "drivers/vulkan/rendering_device_vulkan.h" #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" -#include "vulkan_context_iphone.h" +#include "vulkan_context_ios.h" #import <QuartzCore/CAMetalLayer.h> #ifdef USE_VOLK @@ -48,13 +48,13 @@ #endif #endif -class DisplayServerIPhone : public DisplayServer { - GDCLASS(DisplayServerIPhone, DisplayServer) +class DisplayServerIOS : public DisplayServer { + GDCLASS(DisplayServerIOS, DisplayServer) _THREAD_SAFE_CLASS_ #if defined(VULKAN_ENABLED) - VulkanContextIPhone *context_vulkan = nullptr; + VulkanContextIOS *context_vulkan = nullptr; RenderingDeviceVulkan *rendering_device_vulkan = nullptr; #endif @@ -73,15 +73,15 @@ class DisplayServerIPhone : public DisplayServer { void perform_event(const Ref<InputEvent> &p_event); - DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); - ~DisplayServerIPhone(); + DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + ~DisplayServerIOS(); public: String rendering_driver; - static DisplayServerIPhone *get_singleton(); + static DisplayServerIOS *get_singleton(); - static void register_iphone_driver(); + static void register_ios_driver(); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); @@ -214,4 +214,4 @@ public: void resize_window(CGSize size); }; -#endif /* display_server_iphone_h */ +#endif // DISPLAY_SERVER_IOS_H diff --git a/platform/iphone/display_server_iphone.mm b/platform/ios/display_server_ios.mm index 573ee9b7a8..73d4a2a427 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/ios/display_server_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_iphone.mm */ +/* display_server_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "display_server_iphone.h" +#include "display_server_ios.h" #import "app_delegate.h" #include "core/config/project_settings.h" @@ -37,20 +37,20 @@ #import "godot_view.h" #include "ios.h" #import "keyboard_input_view.h" -#include "os_iphone.h" +#include "os_ios.h" #include "tts_ios.h" #import "view_controller.h" #import <Foundation/Foundation.h> #import <sys/utsname.h> -static const float kDisplayServerIPhoneAcceleration = 1; +static const float kDisplayServerIOSAcceleration = 1.f; -DisplayServerIPhone *DisplayServerIPhone::get_singleton() { - return (DisplayServerIPhone *)DisplayServer::get_singleton(); +DisplayServerIOS *DisplayServerIOS::get_singleton() { + return (DisplayServerIOS *)DisplayServer::get_singleton(); } -DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { rendering_driver = p_rendering_driver; // Init TTS @@ -101,7 +101,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo rendering_device_vulkan = nullptr; if (rendering_driver == "vulkan") { - context_vulkan = memnew(VulkanContextIPhone); + context_vulkan = memnew(VulkanContextIOS); if (context_vulkan->initialize() != OK) { memdelete(context_vulkan); context_vulkan = nullptr; @@ -136,7 +136,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo r_error = OK; } -DisplayServerIPhone::~DisplayServerIPhone() { +DisplayServerIOS::~DisplayServerIOS() { #if defined(VULKAN_ENABLED) if (rendering_device_vulkan) { rendering_device_vulkan->finalize(); @@ -152,11 +152,11 @@ DisplayServerIPhone::~DisplayServerIPhone() { #endif } -DisplayServer *DisplayServerIPhone::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - return memnew(DisplayServerIPhone(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); } -Vector<String> DisplayServerIPhone::get_rendering_drivers_func() { +Vector<String> DisplayServerIOS::get_rendering_drivers_func() { Vector<String> drivers; #if defined(VULKAN_ENABLED) @@ -169,51 +169,52 @@ Vector<String> DisplayServerIPhone::get_rendering_drivers_func() { return drivers; } -void DisplayServerIPhone::register_iphone_driver() { - register_create_function("iphone", create_func, get_rendering_drivers_func); +void DisplayServerIOS::register_ios_driver() { + register_create_function("iOS", create_func, get_rendering_drivers_func); } // MARK: Events -void DisplayServerIPhone::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { window_resize_callback = p_callable; } -void DisplayServerIPhone::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { window_event_callback = p_callable; } -void DisplayServerIPhone::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { input_event_callback = p_callable; } -void DisplayServerIPhone::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { input_text_callback = p_callable; } -void DisplayServerIPhone::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { // Probably not supported for iOS } -void DisplayServerIPhone::process_events() { +void DisplayServerIOS::process_events() { + Input::get_singleton()->flush_buffered_events(); } -void DisplayServerIPhone::_dispatch_input_events(const Ref<InputEvent> &p_event) { - DisplayServerIPhone::get_singleton()->send_input_event(p_event); +void DisplayServerIOS::_dispatch_input_events(const Ref<InputEvent> &p_event) { + DisplayServerIOS::get_singleton()->send_input_event(p_event); } -void DisplayServerIPhone::send_input_event(const Ref<InputEvent> &p_event) const { +void DisplayServerIOS::send_input_event(const Ref<InputEvent> &p_event) const { _window_callback(input_event_callback, p_event); } -void DisplayServerIPhone::send_input_text(const String &p_text) const { +void DisplayServerIOS::send_input_text(const String &p_text) const { _window_callback(input_text_callback, p_text); } -void DisplayServerIPhone::send_window_event(DisplayServer::WindowEvent p_event) const { +void DisplayServerIOS::send_window_event(DisplayServer::WindowEvent p_event) const { _window_callback(window_event_callback, int(p_event)); } -void DisplayServerIPhone::_window_callback(const Callable &p_callable, const Variant &p_arg) const { +void DisplayServerIOS::_window_callback(const Callable &p_callable, const Variant &p_arg) const { if (!p_callable.is_null()) { const Variant *argp = &p_arg; Variant ret; @@ -226,7 +227,7 @@ void DisplayServerIPhone::_window_callback(const Callable &p_callable, const Var // MARK: Touches -void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) { +void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) { if (!GLOBAL_DEF("debug/disable_touch", false)) { Ref<InputEventScreenTouch> ev; ev.instantiate(); @@ -238,7 +239,7 @@ void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_presse } } -void DisplayServerIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { +void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { if (!GLOBAL_DEF("debug/disable_touch", false)) { Ref<InputEventScreenDrag> ev; ev.instantiate(); @@ -249,17 +250,17 @@ void DisplayServerIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int } } -void DisplayServerIPhone::perform_event(const Ref<InputEvent> &p_event) { +void DisplayServerIOS::perform_event(const Ref<InputEvent> &p_event) { Input::get_singleton()->parse_input_event(p_event); } -void DisplayServerIPhone::touches_cancelled(int p_idx) { +void DisplayServerIOS::touches_cancelled(int p_idx) { touch_press(p_idx, -1, -1, false, false); } // MARK: Keyboard -void DisplayServerIPhone::key(Key p_key, bool p_pressed) { +void DisplayServerIOS::key(Key p_key, bool p_pressed) { Ref<InputEventKey> ev; ev.instantiate(); ev->set_echo(false); @@ -272,31 +273,31 @@ void DisplayServerIPhone::key(Key p_key, bool p_pressed) { // MARK: Motion -void DisplayServerIPhone::update_gravity(float p_x, float p_y, float p_z) { +void DisplayServerIOS::update_gravity(float p_x, float p_y, float p_z) { Input::get_singleton()->set_gravity(Vector3(p_x, p_y, p_z)); } -void DisplayServerIPhone::update_accelerometer(float p_x, float p_y, float p_z) { +void DisplayServerIOS::update_accelerometer(float p_x, float p_y, float p_z) { // Found out the Z should not be negated! Pass as is! Vector3 v_accelerometer = Vector3( - p_x / kDisplayServerIPhoneAcceleration, - p_y / kDisplayServerIPhoneAcceleration, - p_z / kDisplayServerIPhoneAcceleration); + p_x / kDisplayServerIOSAcceleration, + p_y / kDisplayServerIOSAcceleration, + p_z / kDisplayServerIOSAcceleration); Input::get_singleton()->set_accelerometer(v_accelerometer); } -void DisplayServerIPhone::update_magnetometer(float p_x, float p_y, float p_z) { +void DisplayServerIOS::update_magnetometer(float p_x, float p_y, float p_z) { Input::get_singleton()->set_magnetometer(Vector3(p_x, p_y, p_z)); } -void DisplayServerIPhone::update_gyroscope(float p_x, float p_y, float p_z) { +void DisplayServerIOS::update_gyroscope(float p_x, float p_y, float p_z) { Input::get_singleton()->set_gyroscope(Vector3(p_x, p_y, p_z)); } // MARK: - -bool DisplayServerIPhone::has_feature(Feature p_feature) const { +bool DisplayServerIOS::has_feature(Feature p_feature) const { switch (p_feature) { // case FEATURE_CURSOR_SHAPE: // case FEATURE_CUSTOM_CURSOR_SHAPE: @@ -321,46 +322,46 @@ bool DisplayServerIPhone::has_feature(Feature p_feature) const { } } -String DisplayServerIPhone::get_name() const { - return "iPhone"; +String DisplayServerIOS::get_name() const { + return "iOS"; } -bool DisplayServerIPhone::tts_is_speaking() const { +bool DisplayServerIOS::tts_is_speaking() const { ERR_FAIL_COND_V(!tts, false); return [tts isSpeaking]; } -bool DisplayServerIPhone::tts_is_paused() const { +bool DisplayServerIOS::tts_is_paused() const { ERR_FAIL_COND_V(!tts, false); return [tts isPaused]; } -Array DisplayServerIPhone::tts_get_voices() const { +Array DisplayServerIOS::tts_get_voices() const { ERR_FAIL_COND_V(!tts, Array()); return [tts getVoices]; } -void DisplayServerIPhone::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { +void DisplayServerIOS::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { ERR_FAIL_COND(!tts); [tts speak:p_text voice:p_voice volume:p_volume pitch:p_pitch rate:p_rate utterance_id:p_utterance_id interrupt:p_interrupt]; } -void DisplayServerIPhone::tts_pause() { +void DisplayServerIOS::tts_pause() { ERR_FAIL_COND(!tts); [tts pauseSpeaking]; } -void DisplayServerIPhone::tts_resume() { +void DisplayServerIOS::tts_resume() { ERR_FAIL_COND(!tts); [tts resumeSpeaking]; } -void DisplayServerIPhone::tts_stop() { +void DisplayServerIOS::tts_stop() { ERR_FAIL_COND(!tts); [tts stopSpeaking]; } -Rect2i DisplayServerIPhone::get_display_safe_area() const { +Rect2i DisplayServerIOS::get_display_safe_area() const { if (@available(iOS 11, *)) { UIEdgeInsets insets = UIEdgeInsetsZero; UIView *view = AppDelegate.viewController.godotView; @@ -376,15 +377,15 @@ Rect2i DisplayServerIPhone::get_display_safe_area() const { } } -int DisplayServerIPhone::get_screen_count() const { +int DisplayServerIOS::get_screen_count() const { return 1; } -Point2i DisplayServerIPhone::screen_get_position(int p_screen) const { +Point2i DisplayServerIOS::screen_get_position(int p_screen) const { return Size2i(); } -Size2i DisplayServerIPhone::screen_get_size(int p_screen) const { +Size2i DisplayServerIOS::screen_get_size(int p_screen) const { CALayer *layer = AppDelegate.viewController.godotView.renderingLayer; if (!layer) { @@ -394,11 +395,11 @@ Size2i DisplayServerIPhone::screen_get_size(int p_screen) const { return Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_scale(p_screen); } -Rect2i DisplayServerIPhone::screen_get_usable_rect(int p_screen) const { +Rect2i DisplayServerIOS::screen_get_usable_rect(int p_screen) const { return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); } -int DisplayServerIPhone::screen_get_dpi(int p_screen) const { +int DisplayServerIOS::screen_get_dpi(int p_screen) const { struct utsname systemInfo; uname(&systemInfo); @@ -435,25 +436,25 @@ int DisplayServerIPhone::screen_get_dpi(int p_screen) const { } } -float DisplayServerIPhone::screen_get_refresh_rate(int p_screen) const { +float DisplayServerIOS::screen_get_refresh_rate(int p_screen) const { return [UIScreen mainScreen].maximumFramesPerSecond; } -float DisplayServerIPhone::screen_get_scale(int p_screen) const { +float DisplayServerIOS::screen_get_scale(int p_screen) const { return [UIScreen mainScreen].nativeScale; } -Vector<DisplayServer::WindowID> DisplayServerIPhone::get_window_list() const { +Vector<DisplayServer::WindowID> DisplayServerIOS::get_window_list() const { Vector<DisplayServer::WindowID> list; list.push_back(MAIN_WINDOW_ID); return list; } -DisplayServer::WindowID DisplayServerIPhone::get_window_at_screen_position(const Point2i &p_position) const { +DisplayServer::WindowID DisplayServerIOS::get_window_at_screen_position(const Point2i &p_position) const { return MAIN_WINDOW_ID; } -int64_t DisplayServerIPhone::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { +int64_t DisplayServerIOS::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { ERR_FAIL_COND_V(p_window != MAIN_WINDOW_ID, 0); switch (p_handle_type) { case DISPLAY_HANDLE: { @@ -471,120 +472,120 @@ int64_t DisplayServerIPhone::window_get_native_handle(HandleType p_handle_type, } } -void DisplayServerIPhone::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { +void DisplayServerIOS::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { window_attached_instance_id = p_instance; } -ObjectID DisplayServerIPhone::window_get_attached_instance_id(WindowID p_window) const { +ObjectID DisplayServerIOS::window_get_attached_instance_id(WindowID p_window) const { return window_attached_instance_id; } -void DisplayServerIPhone::window_set_title(const String &p_title, WindowID p_window) { +void DisplayServerIOS::window_set_title(const String &p_title, WindowID p_window) { // Probably not supported for iOS } -int DisplayServerIPhone::window_get_current_screen(WindowID p_window) const { +int DisplayServerIOS::window_get_current_screen(WindowID p_window) const { return SCREEN_OF_MAIN_WINDOW; } -void DisplayServerIPhone::window_set_current_screen(int p_screen, WindowID p_window) { +void DisplayServerIOS::window_set_current_screen(int p_screen, WindowID p_window) { // Probably not supported for iOS } -Point2i DisplayServerIPhone::window_get_position(WindowID p_window) const { +Point2i DisplayServerIOS::window_get_position(WindowID p_window) const { return Point2i(); } -void DisplayServerIPhone::window_set_position(const Point2i &p_position, WindowID p_window) { +void DisplayServerIOS::window_set_position(const Point2i &p_position, WindowID p_window) { // Probably not supported for single window iOS app } -void DisplayServerIPhone::window_set_transient(WindowID p_window, WindowID p_parent) { +void DisplayServerIOS::window_set_transient(WindowID p_window, WindowID p_parent) { // Probably not supported for iOS } -void DisplayServerIPhone::window_set_max_size(const Size2i p_size, WindowID p_window) { +void DisplayServerIOS::window_set_max_size(const Size2i p_size, WindowID p_window) { // Probably not supported for iOS } -Size2i DisplayServerIPhone::window_get_max_size(WindowID p_window) const { +Size2i DisplayServerIOS::window_get_max_size(WindowID p_window) const { return Size2i(); } -void DisplayServerIPhone::window_set_min_size(const Size2i p_size, WindowID p_window) { +void DisplayServerIOS::window_set_min_size(const Size2i p_size, WindowID p_window) { // Probably not supported for iOS } -Size2i DisplayServerIPhone::window_get_min_size(WindowID p_window) const { +Size2i DisplayServerIOS::window_get_min_size(WindowID p_window) const { return Size2i(); } -void DisplayServerIPhone::window_set_size(const Size2i p_size, WindowID p_window) { +void DisplayServerIOS::window_set_size(const Size2i p_size, WindowID p_window) { // Probably not supported for iOS } -Size2i DisplayServerIPhone::window_get_size(WindowID p_window) const { +Size2i DisplayServerIOS::window_get_size(WindowID p_window) const { CGRect screenBounds = [UIScreen mainScreen].bounds; return Size2i(screenBounds.size.width, screenBounds.size.height) * screen_get_max_scale(); } -Size2i DisplayServerIPhone::window_get_real_size(WindowID p_window) const { +Size2i DisplayServerIOS::window_get_real_size(WindowID p_window) const { return window_get_size(p_window); } -void DisplayServerIPhone::window_set_mode(WindowMode p_mode, WindowID p_window) { +void DisplayServerIOS::window_set_mode(WindowMode p_mode, WindowID p_window) { // Probably not supported for iOS } -DisplayServer::WindowMode DisplayServerIPhone::window_get_mode(WindowID p_window) const { +DisplayServer::WindowMode DisplayServerIOS::window_get_mode(WindowID p_window) const { return WindowMode::WINDOW_MODE_FULLSCREEN; } -bool DisplayServerIPhone::window_is_maximize_allowed(WindowID p_window) const { +bool DisplayServerIOS::window_is_maximize_allowed(WindowID p_window) const { return false; } -void DisplayServerIPhone::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { +void DisplayServerIOS::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { // Probably not supported for iOS } -bool DisplayServerIPhone::window_get_flag(WindowFlags p_flag, WindowID p_window) const { +bool DisplayServerIOS::window_get_flag(WindowFlags p_flag, WindowID p_window) const { return false; } -void DisplayServerIPhone::window_request_attention(WindowID p_window) { +void DisplayServerIOS::window_request_attention(WindowID p_window) { // Probably not supported for iOS } -void DisplayServerIPhone::window_move_to_foreground(WindowID p_window) { +void DisplayServerIOS::window_move_to_foreground(WindowID p_window) { // Probably not supported for iOS } -float DisplayServerIPhone::screen_get_max_scale() const { +float DisplayServerIOS::screen_get_max_scale() const { return screen_get_scale(SCREEN_OF_MAIN_WINDOW); } -void DisplayServerIPhone::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) { +void DisplayServerIOS::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) { screen_orientation = p_orientation; } -DisplayServer::ScreenOrientation DisplayServerIPhone::screen_get_orientation(int p_screen) const { +DisplayServer::ScreenOrientation DisplayServerIOS::screen_get_orientation(int p_screen) const { return screen_orientation; } -bool DisplayServerIPhone::window_can_draw(WindowID p_window) const { +bool DisplayServerIOS::window_can_draw(WindowID p_window) const { return true; } -bool DisplayServerIPhone::can_any_window_draw() const { +bool DisplayServerIOS::can_any_window_draw() const { return true; } -bool DisplayServerIPhone::screen_is_touchscreen(int p_screen) const { +bool DisplayServerIOS::screen_is_touchscreen(int p_screen) const { return true; } -void DisplayServerIPhone::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { +void DisplayServerIOS::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { NSString *existingString = [[NSString alloc] initWithUTF8String:p_existing_text.utf8().get_data()]; [AppDelegate.viewController.keyboardView @@ -594,37 +595,37 @@ void DisplayServerIPhone::virtual_keyboard_show(const String &p_existing_text, c cursorEnd:p_cursor_end]; } -void DisplayServerIPhone::virtual_keyboard_hide() { +void DisplayServerIOS::virtual_keyboard_hide() { [AppDelegate.viewController.keyboardView resignFirstResponder]; } -void DisplayServerIPhone::virtual_keyboard_set_height(int height) { +void DisplayServerIOS::virtual_keyboard_set_height(int height) { virtual_keyboard_height = height * screen_get_max_scale(); } -int DisplayServerIPhone::virtual_keyboard_get_height() const { +int DisplayServerIOS::virtual_keyboard_get_height() const { return virtual_keyboard_height; } -void DisplayServerIPhone::clipboard_set(const String &p_text) { +void DisplayServerIOS::clipboard_set(const String &p_text) { [UIPasteboard generalPasteboard].string = [NSString stringWithUTF8String:p_text.utf8()]; } -String DisplayServerIPhone::clipboard_get() const { +String DisplayServerIOS::clipboard_get() const { NSString *text = [UIPasteboard generalPasteboard].string; return String::utf8([text UTF8String]); } -void DisplayServerIPhone::screen_set_keep_on(bool p_enable) { +void DisplayServerIOS::screen_set_keep_on(bool p_enable) { [UIApplication sharedApplication].idleTimerDisabled = p_enable; } -bool DisplayServerIPhone::screen_is_kept_on() const { +bool DisplayServerIOS::screen_is_kept_on() const { return [UIApplication sharedApplication].idleTimerDisabled; } -void DisplayServerIPhone::resize_window(CGSize viewSize) { +void DisplayServerIOS::resize_window(CGSize viewSize) { Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale(); #if defined(VULKAN_ENABLED) @@ -637,14 +638,14 @@ void DisplayServerIPhone::resize_window(CGSize viewSize) { _window_callback(window_resize_callback, resize_rect); } -void DisplayServerIPhone::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { +void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) context_vulkan->set_vsync_mode(p_window, p_vsync_mode); #endif } -DisplayServer::VSyncMode DisplayServerIPhone::window_get_vsync_mode(WindowID p_window) const { +DisplayServer::VSyncMode DisplayServerIOS::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) return context_vulkan->get_vsync_mode(p_window); diff --git a/platform/iphone/export/export.cpp b/platform/ios/export/export.cpp index 3b02e661c1..6024db2f2c 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/ios/export/export.cpp @@ -30,9 +30,10 @@ #include "export.h" +#include "editor/export/editor_export.h" #include "export_plugin.h" -void register_iphone_exporter() { +void register_ios_exporter() { Ref<EditorExportPlatformIOS> platform; platform.instantiate(); diff --git a/platform/osx/export/export.h b/platform/ios/export/export.h index b386337a09..756a1356ea 100644 --- a/platform/osx/export/export.h +++ b/platform/ios/export/export.h @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OSX_EXPORT_H -#define OSX_EXPORT_H +#ifndef IOS_EXPORT_H +#define IOS_EXPORT_H -void register_osx_exporter(); +void register_ios_exporter(); -#endif // OSX_EXPORT_H +#endif // IOS_EXPORT_H diff --git a/platform/iphone/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 4cf1c279eb..a2e80d33fd 100644 --- a/platform/iphone/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -418,7 +418,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ } // !BAS! I'm assuming the 9 in the original code was a typo. I've added -1 or else it seems to also be adding our terminating zero... - // should apply the same fix in our OSX export. + // should apply the same fix in our macOS export. CharString cs = strnew.utf8(); pfile.resize(cs.size() - 1); for (int i = 0; i < cs.size() - 1; i++) { @@ -1394,7 +1394,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p if (src_pkg_name.is_empty()) { String err; - src_pkg_name = find_export_template("iphone.zip", &err); + src_pkg_name = find_export_template("ios.zip", &err); if (src_pkg_name.is_empty()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found.")); return ERR_FILE_NOT_FOUND; @@ -1444,7 +1444,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p return ERR_SKIP; } - String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".xcframework"; + String library_to_use = "libgodot.ios." + String(p_debug ? "debug" : "release") + ".xcframework"; print_line("Static framework: " + library_to_use); String pkg_name; @@ -1502,7 +1502,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p int ret = unzGoToFirstFile(src_pkg_zip); Vector<uint8_t> project_file_data; while (ret == UNZ_OK) { -#if defined(OSX_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(X11_ENABLED) bool is_execute = false; #endif @@ -1527,17 +1527,17 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p //write - file = file.replace_first("iphone/", ""); + file = file.replace_first("ios/", ""); if (files_to_parse.has(file)) { _fix_config_file(p_preset, data, config_data, p_debug); - } else if (file.begins_with("libgodot.iphone")) { + } else if (file.begins_with("libgodot.ios")) { if (!file.begins_with(library_to_use) || file.ends_with(String("/empty"))) { ret = unzGoToNextFile(src_pkg_zip); continue; //ignore! } found_library = true; -#if defined(OSX_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(X11_ENABLED) is_execute = true; #endif file = file.replace(library_to_use, binary_name + ".xcframework"); @@ -1580,7 +1580,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->store_buffer(data.ptr(), data.size()); } -#if defined(OSX_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(X11_ENABLED) if (is_execute) { // we need execute rights on this file chmod(file.utf8().get_data(), 0755); @@ -1725,7 +1725,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->store_buffer(project_file_data.ptr(), project_file_data.size()); } -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED { if (ep.step("Code-signing dylibs", 2)) { return ERR_SKIP; @@ -1790,7 +1790,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset // Look for export templates (first official, and if defined custom templates). - bool dvalid = exists_export_template("iphone.zip", &err); + bool dvalid = exists_export_template("ios.zip", &err); bool rvalid = dvalid; // Both in the same ZIP. if (p_preset->get("custom_template/debug") != "") { @@ -1838,12 +1838,8 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset } EditorExportPlatformIOS::EditorExportPlatformIOS() { - Ref<Image> img = memnew(Image(_iphone_logo)); - logo.instantiate(); - logo->create_from_image(img); - + logo = ImageTexture::create_from_image(memnew(Image(_ios_logo))); plugins_changed.set(); - check_for_changes_thread.start(_check_for_changes_poll_thread, this); } diff --git a/platform/iphone/export/export_plugin.h b/platform/ios/export/export_plugin.h index 1db7418e3f..ce470bba78 100644 --- a/platform/iphone/export/export_plugin.h +++ b/platform/ios/export/export_plugin.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IPHONE_EXPORT_PLUGIN_H -#define IPHONE_EXPORT_PLUGIN_H +#ifndef IOS_EXPORT_PLUGIN_H +#define IOS_EXPORT_PLUGIN_H #include "core/config/project_settings.h" #include "core/io/file_access.h" @@ -40,10 +40,10 @@ #include "core/os/os.h" #include "core/templates/safe_refcount.h" #include "core/version.h" -#include "editor/editor_export.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export_platform.h" #include "main/splash.gen.h" -#include "platform/iphone/logo.gen.h" +#include "platform/ios/logo.gen.h" #include "string.h" #include "godot_plugin_config.h" @@ -290,4 +290,4 @@ public: } }; -#endif +#endif // IOS_EXPORT_PLUGIN_H diff --git a/platform/iphone/export/godot_plugin_config.cpp b/platform/ios/export/godot_plugin_config.cpp index 9118b95337..9118b95337 100644 --- a/platform/iphone/export/godot_plugin_config.cpp +++ b/platform/ios/export/godot_plugin_config.cpp diff --git a/platform/iphone/export/godot_plugin_config.h b/platform/ios/export/godot_plugin_config.h index 9ef8aa8c6d..5ca8b05b42 100644 --- a/platform/iphone/export/godot_plugin_config.h +++ b/platform/ios/export/godot_plugin_config.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IPHONE_GODOT_PLUGIN_CONFIG_H -#define IPHONE_GODOT_PLUGIN_CONFIG_H +#ifndef IOS_GODOT_PLUGIN_CONFIG_H +#define IOS_GODOT_PLUGIN_CONFIG_H #include "core/error/error_list.h" #include "core/io/config_file.h" @@ -129,4 +129,4 @@ struct PluginConfigIOS { static PluginConfigIOS load_plugin_config(Ref<ConfigFile> config_file, const String &path); }; -#endif // GODOT_PLUGIN_CONFIG_H +#endif // IOS_GODOT_PLUGIN_CONFIG_H diff --git a/platform/iphone/godot_app_delegate.h b/platform/ios/godot_app_delegate.h index 703a906bda..703a906bda 100644 --- a/platform/iphone/godot_app_delegate.h +++ b/platform/ios/godot_app_delegate.h diff --git a/platform/iphone/godot_app_delegate.m b/platform/ios/godot_app_delegate.m index 84347f9a30..84347f9a30 100644 --- a/platform/iphone/godot_app_delegate.m +++ b/platform/ios/godot_app_delegate.m diff --git a/platform/iphone/godot_iphone.mm b/platform/ios/godot_ios.mm index 49474ef554..5f3e786b8a 100644 --- a/platform/iphone/godot_iphone.mm +++ b/platform/ios/godot_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_iphone.mm */ +/* godot_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,17 +30,17 @@ #include "core/string/ustring.h" #include "main/main.h" -#include "os_iphone.h" +#include "os_ios.h" #include <stdio.h> #include <string.h> #include <unistd.h> -static OSIPhone *os = nullptr; +static OS_IOS *os = nullptr; int add_path(int, char **); int add_cmdline(int, char **); -int iphone_main(int, char **, String); +int ios_main(int, char **, String); int add_path(int p_argc, char **p_args) { NSString *str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"]; @@ -74,7 +74,7 @@ int add_cmdline(int p_argc, char **p_args) { return p_argc; } -int iphone_main(int argc, char **argv, String data_dir, String cache_dir) { +int ios_main(int argc, char **argv, String data_dir, String cache_dir) { size_t len = strlen(argv[0]); while (len--) { @@ -91,11 +91,11 @@ int iphone_main(int argc, char **argv, String data_dir, String cache_dir) { chdir(path); } - printf("godot_iphone %s\n", argv[0]); + printf("godot_ios %s\n", argv[0]); char cwd[512]; getcwd(cwd, sizeof(cwd)); printf("cwd %s\n", cwd); - os = new OSIPhone(data_dir, cache_dir); + os = new OS_IOS(data_dir, cache_dir); // We must override main when testing is enabled TEST_MAIN_OVERRIDE @@ -112,7 +112,10 @@ int iphone_main(int argc, char **argv, String data_dir, String cache_dir) { Error err = Main::setup(fargv[0], argc - 1, &fargv[1], false); printf("setup %i\n", err); - if (err != OK) { + + if (err == ERR_HELP) { // Returned by --help and --version, so success. + return 0; + } else if (err != OK) { return 255; } @@ -121,8 +124,8 @@ int iphone_main(int argc, char **argv, String data_dir, String cache_dir) { return 0; } -void iphone_finish() { - printf("iphone_finish\n"); +void ios_finish() { + printf("ios_finish\n"); Main::cleanup(); delete os; } diff --git a/platform/iphone/godot_view.h b/platform/ios/godot_view.h index fcb97fa63a..fcb97fa63a 100644 --- a/platform/iphone/godot_view.h +++ b/platform/ios/godot_view.h diff --git a/platform/iphone/godot_view.mm b/platform/ios/godot_view.mm index e48dd2e507..9ed219508c 100644 --- a/platform/iphone/godot_view.mm +++ b/platform/ios/godot_view.mm @@ -33,7 +33,7 @@ #include "core/os/keyboard.h" #include "core/string/ustring.h" #import "display_layer.h" -#include "display_server_iphone.h" +#include "display_server_ios.h" #import "godot_view_gesture_recognizer.h" #import "godot_view_renderer.h" @@ -281,8 +281,8 @@ static const float earth_gravity = 9.80665; self.renderingLayer.frame = self.bounds; [self.renderingLayer layoutDisplayLayer]; - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->resize_window(self.bounds.size); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->resize_window(self.bounds.size); } } @@ -348,7 +348,7 @@ static const float earth_gravity = 9.80665; int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; - DisplayServerIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1); + DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1); } } } @@ -362,7 +362,7 @@ static const float earth_gravity = 9.80665; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; CGPoint prev_point = [touch previousLocationInView:self]; - DisplayServerIPhone::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor); + DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor); } } } @@ -376,7 +376,7 @@ static const float earth_gravity = 9.80665; ERR_FAIL_COND(tid == -1); [self removeTouch:touch]; CGPoint touchPoint = [touch locationInView:self]; - DisplayServerIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false); + DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false); } } } @@ -388,7 +388,7 @@ static const float earth_gravity = 9.80665; UITouch *touch = [tlist objectAtIndex:i]; int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); - DisplayServerIPhone::get_singleton()->touches_cancelled(tid); + DisplayServerIOS::get_singleton()->touches_cancelled(tid); } } [self clearTouches]; @@ -452,28 +452,28 @@ static const float earth_gravity = 9.80665; switch (interfaceOrientation) { case UIInterfaceOrientationLandscapeLeft: { - DisplayServerIPhone::get_singleton()->update_gravity(-gravity.y, gravity.x, gravity.z); - DisplayServerIPhone::get_singleton()->update_accelerometer(-(acceleration.y + gravity.y), (acceleration.x + gravity.x), acceleration.z + gravity.z); - DisplayServerIPhone::get_singleton()->update_magnetometer(-magnetic.y, magnetic.x, magnetic.z); - DisplayServerIPhone::get_singleton()->update_gyroscope(-rotation.y, rotation.x, rotation.z); + DisplayServerIOS::get_singleton()->update_gravity(-gravity.y, gravity.x, gravity.z); + DisplayServerIOS::get_singleton()->update_accelerometer(-(acceleration.y + gravity.y), (acceleration.x + gravity.x), acceleration.z + gravity.z); + DisplayServerIOS::get_singleton()->update_magnetometer(-magnetic.y, magnetic.x, magnetic.z); + DisplayServerIOS::get_singleton()->update_gyroscope(-rotation.y, rotation.x, rotation.z); } break; case UIInterfaceOrientationLandscapeRight: { - DisplayServerIPhone::get_singleton()->update_gravity(gravity.y, -gravity.x, gravity.z); - DisplayServerIPhone::get_singleton()->update_accelerometer((acceleration.y + gravity.y), -(acceleration.x + gravity.x), acceleration.z + gravity.z); - DisplayServerIPhone::get_singleton()->update_magnetometer(magnetic.y, -magnetic.x, magnetic.z); - DisplayServerIPhone::get_singleton()->update_gyroscope(rotation.y, -rotation.x, rotation.z); + DisplayServerIOS::get_singleton()->update_gravity(gravity.y, -gravity.x, gravity.z); + DisplayServerIOS::get_singleton()->update_accelerometer((acceleration.y + gravity.y), -(acceleration.x + gravity.x), acceleration.z + gravity.z); + DisplayServerIOS::get_singleton()->update_magnetometer(magnetic.y, -magnetic.x, magnetic.z); + DisplayServerIOS::get_singleton()->update_gyroscope(rotation.y, -rotation.x, rotation.z); } break; case UIInterfaceOrientationPortraitUpsideDown: { - DisplayServerIPhone::get_singleton()->update_gravity(-gravity.x, gravity.y, gravity.z); - DisplayServerIPhone::get_singleton()->update_accelerometer(-(acceleration.x + gravity.x), (acceleration.y + gravity.y), acceleration.z + gravity.z); - DisplayServerIPhone::get_singleton()->update_magnetometer(-magnetic.x, magnetic.y, magnetic.z); - DisplayServerIPhone::get_singleton()->update_gyroscope(-rotation.x, rotation.y, rotation.z); + DisplayServerIOS::get_singleton()->update_gravity(-gravity.x, gravity.y, gravity.z); + DisplayServerIOS::get_singleton()->update_accelerometer(-(acceleration.x + gravity.x), (acceleration.y + gravity.y), acceleration.z + gravity.z); + DisplayServerIOS::get_singleton()->update_magnetometer(-magnetic.x, magnetic.y, magnetic.z); + DisplayServerIOS::get_singleton()->update_gyroscope(-rotation.x, rotation.y, rotation.z); } break; default: { // assume portrait - DisplayServerIPhone::get_singleton()->update_gravity(gravity.x, gravity.y, gravity.z); - DisplayServerIPhone::get_singleton()->update_accelerometer(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z); - DisplayServerIPhone::get_singleton()->update_magnetometer(magnetic.x, magnetic.y, magnetic.z); - DisplayServerIPhone::get_singleton()->update_gyroscope(rotation.x, rotation.y, rotation.z); + DisplayServerIOS::get_singleton()->update_gravity(gravity.x, gravity.y, gravity.z); + DisplayServerIOS::get_singleton()->update_accelerometer(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z); + DisplayServerIOS::get_singleton()->update_magnetometer(magnetic.x, magnetic.y, magnetic.z); + DisplayServerIOS::get_singleton()->update_gyroscope(rotation.x, rotation.y, rotation.z); } break; } } diff --git a/platform/iphone/godot_view_gesture_recognizer.h b/platform/ios/godot_view_gesture_recognizer.h index 9fd8a6b222..9fd8a6b222 100644 --- a/platform/iphone/godot_view_gesture_recognizer.h +++ b/platform/ios/godot_view_gesture_recognizer.h diff --git a/platform/iphone/godot_view_gesture_recognizer.mm b/platform/ios/godot_view_gesture_recognizer.mm index 49a92add5e..49a92add5e 100644 --- a/platform/iphone/godot_view_gesture_recognizer.mm +++ b/platform/ios/godot_view_gesture_recognizer.mm diff --git a/platform/iphone/godot_view_renderer.h b/platform/ios/godot_view_renderer.h index b3ee23ae4f..b3ee23ae4f 100644 --- a/platform/iphone/godot_view_renderer.h +++ b/platform/ios/godot_view_renderer.h diff --git a/platform/iphone/godot_view_renderer.mm b/platform/ios/godot_view_renderer.mm index 32477ae41c..140410fbef 100644 --- a/platform/iphone/godot_view_renderer.mm +++ b/platform/ios/godot_view_renderer.mm @@ -32,9 +32,9 @@ #include "core/config/project_settings.h" #include "core/os/keyboard.h" -#import "display_server_iphone.h" +#import "display_server_ios.h" #include "main/main.h" -#include "os_iphone.h" +#include "os_ios.h" #include "servers/audio_server.h" #import <AudioToolbox/AudioServices.h> @@ -69,7 +69,7 @@ if (!self.hasStartedMain) { self.hasStartedMain = YES; - OSIPhone::get_singleton()->start(); + OS_IOS::get_singleton()->start(); return YES; } @@ -108,11 +108,11 @@ } - (void)renderOnView:(UIView *)view { - if (!OSIPhone::get_singleton()) { + if (!OS_IOS::get_singleton()) { return; } - OSIPhone::get_singleton()->iterate(); + OS_IOS::get_singleton()->iterate(); } @end diff --git a/platform/iphone/ios.h b/platform/ios/ios.h index 0607d7b395..0b3842b233 100644 --- a/platform/iphone/ios.h +++ b/platform/ios/ios.h @@ -58,4 +58,4 @@ public: iOS(); }; -#endif +#endif // IOS_H diff --git a/platform/iphone/ios.mm b/platform/ios/ios.mm index 79baae028a..79baae028a 100644 --- a/platform/iphone/ios.mm +++ b/platform/ios/ios.mm diff --git a/platform/iphone/joypad_iphone.h b/platform/ios/joypad_ios.h index 37e272a2c9..66c4b090bc 100644 --- a/platform/iphone/joypad_iphone.h +++ b/platform/ios/joypad_ios.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joypad_iphone.h */ +/* joypad_ios.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,7 +30,7 @@ #import <GameController/GameController.h> -@interface JoypadIPhoneObserver : NSObject +@interface JoypadIOSObserver : NSObject - (void)startObserving; - (void)startProcessing; @@ -38,13 +38,13 @@ @end -class JoypadIPhone { +class JoypadIOS { private: - JoypadIPhoneObserver *observer; + JoypadIOSObserver *observer; public: - JoypadIPhone(); - ~JoypadIPhone(); + JoypadIOS(); + ~JoypadIOS(); void start_processing(); }; diff --git a/platform/iphone/joypad_iphone.mm b/platform/ios/joypad_ios.mm index 9c2feeaaca..e147cb2527 100644 --- a/platform/iphone/joypad_iphone.mm +++ b/platform/ios/joypad_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joypad_iphone.mm */ +/* joypad_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#import "joypad_iphone.h" +#import "joypad_ios.h" #include "core/config/project_settings.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" @@ -36,27 +36,27 @@ #import "godot_view.h" -#include "os_iphone.h" +#include "os_ios.h" -JoypadIPhone::JoypadIPhone() { - observer = [[JoypadIPhoneObserver alloc] init]; +JoypadIOS::JoypadIOS() { + observer = [[JoypadIOSObserver alloc] init]; [observer startObserving]; } -JoypadIPhone::~JoypadIPhone() { +JoypadIOS::~JoypadIOS() { if (observer) { [observer finishObserving]; observer = nil; } } -void JoypadIPhone::start_processing() { +void JoypadIOS::start_processing() { if (observer) { [observer startProcessing]; } } -@interface JoypadIPhoneObserver () +@interface JoypadIOSObserver () @property(assign, nonatomic) BOOL isObserving; @property(assign, nonatomic) BOOL isProcessing; @@ -65,7 +65,7 @@ void JoypadIPhone::start_processing() { @end -@implementation JoypadIPhoneObserver +@implementation JoypadIOSObserver - (instancetype)init { self = [super init]; diff --git a/platform/iphone/keyboard_input_view.h b/platform/ios/keyboard_input_view.h index 33fa5d571a..33fa5d571a 100644 --- a/platform/iphone/keyboard_input_view.h +++ b/platform/ios/keyboard_input_view.h diff --git a/platform/iphone/keyboard_input_view.mm b/platform/ios/keyboard_input_view.mm index f2a7b22483..76e3f23c9d 100644 --- a/platform/iphone/keyboard_input_view.mm +++ b/platform/ios/keyboard_input_view.mm @@ -31,8 +31,8 @@ #import "keyboard_input_view.h" #include "core/os/keyboard.h" -#include "display_server_iphone.h" -#include "os_iphone.h" +#include "display_server_ios.h" +#include "os_ios.h" @interface GodotKeyboardInputView () <UITextViewDelegate> @@ -115,8 +115,8 @@ - (void)deleteText:(NSInteger)charactersToDelete { for (int i = 0; i < charactersToDelete; i++) { - DisplayServerIPhone::get_singleton()->key(Key::BACKSPACE, true); - DisplayServerIPhone::get_singleton()->key(Key::BACKSPACE, false); + DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, true); + DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, false); } } @@ -138,8 +138,8 @@ break; } - DisplayServerIPhone::get_singleton()->key((Key)character, true); - DisplayServerIPhone::get_singleton()->key((Key)character, false); + DisplayServerIOS::get_singleton()->key((Key)character, true); + DisplayServerIOS::get_singleton()->key((Key)character, false); } } diff --git a/platform/iphone/logo.png b/platform/ios/logo.png Binary files differindex 966d8aa70a..966d8aa70a 100644 --- a/platform/iphone/logo.png +++ b/platform/ios/logo.png diff --git a/platform/iphone/main.m b/platform/ios/main.m index acfa7ab731..acfa7ab731 100644 --- a/platform/iphone/main.m +++ b/platform/ios/main.m diff --git a/platform/iphone/os_iphone.h b/platform/ios/os_ios.h index d03403bbb4..cfd1771653 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/ios/os_ios.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_iphone.h */ +/* os_ios.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,24 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef IPHONE_ENABLED +#ifdef IOS_ENABLED -#ifndef OS_IPHONE_H -#define OS_IPHONE_H +#ifndef OS_IOS_H +#define OS_IOS_H #include "drivers/coreaudio/audio_driver_coreaudio.h" #include "drivers/unix/os_unix.h" #include "ios.h" -#include "joypad_iphone.h" +#include "joypad_ios.h" #include "servers/audio_server.h" #include "servers/rendering/renderer_compositor.h" #if defined(VULKAN_ENABLED) #include "drivers/vulkan/rendering_device_vulkan.h" -#include "platform/iphone/vulkan_context_iphone.h" +#include "platform/ios/vulkan_context_ios.h" #endif -class OSIPhone : public OS_Unix { +class OS_IOS : public OS_Unix { private: static HashMap<String, void *> dynamic_symbol_lookup_table; friend void register_dynamic_symbol(char *name, void *address); @@ -54,7 +54,7 @@ private: iOS *ios = nullptr; - JoypadIPhone *joypad_iphone = nullptr; + JoypadIOS *joypad_ios = nullptr; MainLoop *main_loop = nullptr; @@ -79,10 +79,10 @@ private: void deinitialize_modules(); public: - static OSIPhone *get_singleton(); + static OS_IOS *get_singleton(); - OSIPhone(String p_data_dir, String p_cache_dir); - ~OSIPhone(); + OS_IOS(String p_data_dir, String p_cache_dir); + ~OS_IOS(); void initialize_modules(); @@ -119,6 +119,6 @@ public: void on_focus_in(); }; -#endif // OS_IPHONE_H +#endif // OS_IOS_H -#endif // IPHONE_ENABLED +#endif // OS_IOS_H diff --git a/platform/iphone/os_iphone.mm b/platform/ios/os_ios.mm index 95b06b728e..880315209e 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/ios/os_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_iphone.mm */ +/* os_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef IPHONE_ENABLED +#ifdef IOS_ENABLED -#include "os_iphone.h" +#include "os_ios.h" #import "app_delegate.h" #include "core/config/project_settings.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/file_access_pack.h" -#include "display_server_iphone.h" +#include "display_server_ios.h" #include "drivers/unix/syslog_logger.h" #import "godot_view.h" #include "main/main.h" @@ -65,7 +65,7 @@ typedef void (*init_callback)(); static init_callback *ios_init_callbacks = nullptr; static int ios_init_callbacks_count = 0; static int ios_init_callbacks_capacity = 0; -HashMap<String, void *> OSIPhone::dynamic_symbol_lookup_table; +HashMap<String, void *> OS_IOS::dynamic_symbol_lookup_table; void add_ios_init_callback(init_callback cb) { if (ios_init_callbacks_count == ios_init_callbacks_capacity) { @@ -82,14 +82,14 @@ void add_ios_init_callback(init_callback cb) { } void register_dynamic_symbol(char *name, void *address) { - OSIPhone::dynamic_symbol_lookup_table[String(name)] = address; + OS_IOS::dynamic_symbol_lookup_table[String(name)] = address; } -OSIPhone *OSIPhone::get_singleton() { - return (OSIPhone *)OS::get_singleton(); +OS_IOS *OS_IOS::get_singleton() { + return (OS_IOS *)OS::get_singleton(); } -OSIPhone::OSIPhone(String p_data_dir, String p_cache_dir) { +OS_IOS::OS_IOS(String p_data_dir, String p_cache_dir) { for (int i = 0; i < ios_init_callbacks_count; ++i) { ios_init_callbacks[i](); } @@ -116,37 +116,37 @@ OSIPhone::OSIPhone(String p_data_dir, String p_cache_dir) { AudioDriverManager::add_driver(&audio_driver); - DisplayServerIPhone::register_iphone_driver(); + DisplayServerIOS::register_ios_driver(); } -OSIPhone::~OSIPhone() {} +OS_IOS::~OS_IOS() {} -void OSIPhone::alert(const String &p_alert, const String &p_title) { +void OS_IOS::alert(const String &p_alert, const String &p_title) { const CharString utf8_alert = p_alert.utf8(); const CharString utf8_title = p_title.utf8(); iOS::alert(utf8_alert.get_data(), utf8_title.get_data()); } -void OSIPhone::initialize_core() { +void OS_IOS::initialize_core() { OS_Unix::initialize_core(); set_user_data_dir(user_data_dir); } -void OSIPhone::initialize() { +void OS_IOS::initialize() { initialize_core(); } -void OSIPhone::initialize_modules() { +void OS_IOS::initialize_modules() { ios = memnew(iOS); Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", ios)); - joypad_iphone = memnew(JoypadIPhone); + joypad_ios = memnew(JoypadIOS); } -void OSIPhone::deinitialize_modules() { - if (joypad_iphone) { - memdelete(joypad_iphone); +void OS_IOS::deinitialize_modules() { + if (joypad_ios) { + memdelete(joypad_ios); } if (ios) { @@ -154,7 +154,7 @@ void OSIPhone::deinitialize_modules() { } } -void OSIPhone::set_main_loop(MainLoop *p_main_loop) { +void OS_IOS::set_main_loop(MainLoop *p_main_loop) { main_loop = p_main_loop; if (main_loop) { @@ -162,11 +162,11 @@ void OSIPhone::set_main_loop(MainLoop *p_main_loop) { } } -MainLoop *OSIPhone::get_main_loop() const { +MainLoop *OS_IOS::get_main_loop() const { return main_loop; } -void OSIPhone::delete_main_loop() { +void OS_IOS::delete_main_loop() { if (main_loop) { main_loop->finalize(); memdelete(main_loop); @@ -175,7 +175,7 @@ void OSIPhone::delete_main_loop() { main_loop = nullptr; } -bool OSIPhone::iterate() { +bool OS_IOS::iterate() { if (!main_loop) { return true; } @@ -187,15 +187,15 @@ bool OSIPhone::iterate() { return Main::iteration(); } -void OSIPhone::start() { +void OS_IOS::start() { Main::start(); - if (joypad_iphone) { - joypad_iphone->start_processing(); + if (joypad_ios) { + joypad_ios->start_processing(); } } -void OSIPhone::finalize() { +void OS_IOS::finalize() { deinitialize_modules(); // Already gets called @@ -204,7 +204,7 @@ void OSIPhone::finalize() { // MARK: Dynamic Libraries -Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { +Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { if (p_path.length() == 0) { p_library_handle = RTLD_SELF; @@ -217,16 +217,16 @@ Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handl return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path, r_resolved_path); } -Error OSIPhone::close_dynamic_library(void *p_library_handle) { +Error OS_IOS::close_dynamic_library(void *p_library_handle) { if (p_library_handle == RTLD_SELF) { return OK; } return OS_Unix::close_dynamic_library(p_library_handle); } -Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { +Error OS_IOS::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); + void **ptr = OS_IOS::dynamic_symbol_lookup_table.getptr(p_name); if (ptr) { p_symbol_handle = *ptr; return OK; @@ -235,11 +235,11 @@ Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional); } -String OSIPhone::get_name() const { +String OS_IOS::get_name() const { return "iOS"; } -String OSIPhone::get_model_name() const { +String OS_IOS::get_model_name() const { String model = ios->get_model(); if (model != "") { return model; @@ -248,7 +248,7 @@ String OSIPhone::get_model_name() const { return OS_Unix::get_model_name(); } -Error OSIPhone::shell_open(String p_uri) { +Error OS_IOS::shell_open(String p_uri) { NSString *urlPath = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()]; NSURL *url = [NSURL URLWithString:urlPath]; @@ -263,21 +263,21 @@ Error OSIPhone::shell_open(String p_uri) { return OK; } -void OSIPhone::set_user_data_dir(String p_dir) { +void OS_IOS::set_user_data_dir(String p_dir) { Ref<DirAccess> da = DirAccess::open(p_dir); user_data_dir = da->get_current_dir(); printf("setting data dir to %s from %s\n", user_data_dir.utf8().get_data(), p_dir.utf8().get_data()); } -String OSIPhone::get_user_data_dir() const { +String OS_IOS::get_user_data_dir() const { return user_data_dir; } -String OSIPhone::get_cache_path() const { +String OS_IOS::get_cache_path() const { return cache_dir; } -String OSIPhone::get_locale() const { +String OS_IOS::get_locale() const { NSString *preferedLanguage = [NSLocale preferredLanguages].firstObject; if (preferedLanguage) { @@ -288,12 +288,12 @@ String OSIPhone::get_locale() const { return String::utf8([localeIdentifier UTF8String]).replace("-", "_"); } -String OSIPhone::get_unique_id() const { +String OS_IOS::get_unique_id() const { NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString; return String::utf8([uuid UTF8String]); } -String OSIPhone::get_processor_name() const { +String OS_IOS::get_processor_name() const { char buffer[256]; size_t buffer_len = 256; if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, NULL, 0) == 0) { @@ -302,7 +302,7 @@ String OSIPhone::get_processor_name() const { ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string.")); } -void OSIPhone::vibrate_handheld(int p_duration_ms) { +void OS_IOS::vibrate_handheld(int p_duration_ms) { if (ios->supports_haptic_engine()) { ios->vibrate_haptic_engine((float)p_duration_ms / 1000.f); } else { @@ -311,16 +311,16 @@ void OSIPhone::vibrate_handheld(int p_duration_ms) { } } -bool OSIPhone::_check_internal_feature_support(const String &p_feature) { +bool OS_IOS::_check_internal_feature_support(const String &p_feature) { return p_feature == "mobile"; } -void OSIPhone::on_focus_out() { +void OS_IOS::on_focus_out() { if (is_focused) { is_focused = false; - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT); } [AppDelegate.viewController.godotView stopRendering]; @@ -329,12 +329,12 @@ void OSIPhone::on_focus_out() { } } -void OSIPhone::on_focus_in() { +void OS_IOS::on_focus_in() { if (!is_focused) { is_focused = true; - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN); } [AppDelegate.viewController.godotView startRendering]; @@ -343,4 +343,4 @@ void OSIPhone::on_focus_in() { } } -#endif // IPHONE_ENABLED +#endif // IOS_ENABLED diff --git a/platform/iphone/platform_config.h b/platform/ios/platform_config.h index fed77d8932..fed77d8932 100644 --- a/platform/iphone/platform_config.h +++ b/platform/ios/platform_config.h diff --git a/platform/iphone/tts_ios.h b/platform/ios/tts_ios.h index 064316b0b2..064316b0b2 100644 --- a/platform/iphone/tts_ios.h +++ b/platform/ios/tts_ios.h diff --git a/platform/iphone/tts_ios.mm b/platform/ios/tts_ios.mm index a079d02add..a079d02add 100644 --- a/platform/iphone/tts_ios.mm +++ b/platform/ios/tts_ios.mm diff --git a/platform/iphone/view_controller.h b/platform/ios/view_controller.h index c8b37a4d11..c8b37a4d11 100644 --- a/platform/iphone/view_controller.h +++ b/platform/ios/view_controller.h diff --git a/platform/iphone/view_controller.mm b/platform/ios/view_controller.mm index 4f4ef4f046..43669d3f94 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/ios/view_controller.mm @@ -30,11 +30,11 @@ #import "view_controller.h" #include "core/config/project_settings.h" -#include "display_server_iphone.h" +#include "display_server_ios.h" #import "godot_view.h" #import "godot_view_renderer.h" #import "keyboard_input_view.h" -#include "os_iphone.h" +#include "os_ios.h" #import <AVFoundation/AVFoundation.h> #import <GameController/GameController.h> @@ -168,11 +168,11 @@ } - (BOOL)shouldAutorotate { - if (!DisplayServerIPhone::get_singleton()) { + if (!DisplayServerIOS::get_singleton()) { return NO; } - switch (DisplayServerIPhone::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { + switch (DisplayServerIOS::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { case DisplayServer::SCREEN_SENSOR: case DisplayServer::SCREEN_SENSOR_LANDSCAPE: case DisplayServer::SCREEN_SENSOR_PORTRAIT: @@ -183,11 +183,11 @@ } - (UIInterfaceOrientationMask)supportedInterfaceOrientations { - if (!DisplayServerIPhone::get_singleton()) { + if (!DisplayServerIOS::get_singleton()) { return UIInterfaceOrientationMaskAll; } - switch (DisplayServerIPhone::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { + switch (DisplayServerIOS::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { case DisplayServer::SCREEN_PORTRAIT: return UIInterfaceOrientationMaskPortrait; case DisplayServer::SCREEN_REVERSE_LANDSCAPE: @@ -226,14 +226,14 @@ CGRect rawFrame = [value CGRectValue]; CGRect keyboardFrame = [self.view convertRect:rawFrame fromView:nil]; - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->virtual_keyboard_set_height(keyboardFrame.size.height); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->virtual_keyboard_set_height(keyboardFrame.size.height); } } - (void)keyboardHidden:(NSNotification *)notification { - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->virtual_keyboard_set_height(0); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->virtual_keyboard_set_height(0); } } diff --git a/platform/iphone/vulkan_context_iphone.h b/platform/ios/vulkan_context_ios.h index 7576525755..e9c09e087a 100644 --- a/platform/iphone/vulkan_context_iphone.h +++ b/platform/ios/vulkan_context_ios.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* vulkan_context_iphone.h */ +/* vulkan_context_ios.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,21 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VULKAN_CONTEXT_IPHONE_H -#define VULKAN_CONTEXT_IPHONE_H +#ifndef VULKAN_CONTEXT_IOS_H +#define VULKAN_CONTEXT_IOS_H #include "drivers/vulkan/vulkan_context.h" #import <UIKit/UIKit.h> -class VulkanContextIPhone : public VulkanContext { +class VulkanContextIOS : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height); - VulkanContextIPhone(); - ~VulkanContextIPhone(); + VulkanContextIOS(); + ~VulkanContextIOS(); }; -#endif // VULKAN_CONTEXT_IPHONE_H +#endif // VULKAN_CONTEXT_IOS_H diff --git a/platform/iphone/vulkan_context_iphone.mm b/platform/ios/vulkan_context_ios.mm index 17cb0f6009..09cd369aa5 100644 --- a/platform/iphone/vulkan_context_iphone.mm +++ b/platform/ios/vulkan_context_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* vulkan_context_iphone.mm */ +/* vulkan_context_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,18 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "vulkan_context_iphone.h" +#include "vulkan_context_ios.h" #ifdef USE_VOLK #include <volk.h> #else #include <vulkan/vulkan.h> #endif -const char *VulkanContextIPhone::_get_platform_surface_extension() const { +const char *VulkanContextIOS::_get_platform_surface_extension() const { return VK_MVK_IOS_SURFACE_EXTENSION_NAME; } -Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height) { +Error VulkanContextIOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height) { VkIOSSurfaceCreateInfoMVK createInfo; createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = nullptr; @@ -54,6 +54,6 @@ Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, Di return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } -VulkanContextIPhone::VulkanContextIPhone() {} +VulkanContextIOS::VulkanContextIOS() {} -VulkanContextIPhone::~VulkanContextIPhone() {} +VulkanContextIOS::~VulkanContextIOS() {} diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h index b7b0b3ac96..807e2f936b 100644 --- a/platform/javascript/audio_driver_javascript.h +++ b/platform/javascript/audio_driver_javascript.h @@ -158,4 +158,4 @@ public: }; #endif -#endif +#endif // AUDIO_DRIVER_JAVASCRIPT_H diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index a96c539a1f..4edd6c793a 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -236,7 +236,7 @@ void DisplayServerJavaScript::mouse_move_callback(double p_x, double p_y, double const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape p_shape) { switch (p_shape) { case DisplayServer::CURSOR_ARROW: - return "auto"; + return "default"; case DisplayServer::CURSOR_IBEAM: return "text"; case DisplayServer::CURSOR_POINTING_HAND: @@ -270,7 +270,7 @@ const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape case DisplayServer::CURSOR_HELP: return "help"; default: - return "auto"; + return "default"; } } diff --git a/platform/javascript/export/export.h b/platform/javascript/export/export.h index 41cc66cfb8..29c335ed0e 100644 --- a/platform/javascript/export/export.h +++ b/platform/javascript/export/export.h @@ -33,4 +33,4 @@ void register_javascript_exporter(); -#endif +#endif // JAVASCRIPT_EXPORT_H diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp index 901580c140..e2ae45627e 100644 --- a/platform/javascript/export/export_plugin.cpp +++ b/platform/javascript/export/export_plugin.cpp @@ -661,13 +661,8 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { server.instantiate(); server_thread.start(_server_thread_poll, this); - Ref<Image> img = memnew(Image(_javascript_logo)); - logo.instantiate(); - logo->create_from_image(img); - - img = Ref<Image>(memnew(Image(_javascript_run_icon))); - run_icon.instantiate(); - run_icon->create_from_image(img); + logo = ImageTexture::create_from_image(memnew(Image(_javascript_logo))); + run_icon = ImageTexture::create_from_image(memnew(Image(_javascript_run_icon))); Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); if (theme.is_valid()) { diff --git a/platform/javascript/export/export_plugin.h b/platform/javascript/export/export_plugin.h index 1aaec5454d..e6ca5976df 100644 --- a/platform/javascript/export/export_plugin.h +++ b/platform/javascript/export/export_plugin.h @@ -36,8 +36,8 @@ #include "core/io/stream_peer_ssl.h" #include "core/io/tcp_server.h" #include "core/io/zip_io.h" -#include "editor/editor_export.h" #include "editor/editor_node.h" +#include "editor/export/editor_export_platform.h" #include "main/splash.gen.h" #include "platform/javascript/logo.gen.h" #include "platform/javascript/run_icon.gen.h" @@ -144,4 +144,4 @@ public: ~EditorExportPlatformJavaScript(); }; -#endif +#endif // JAVASCRIPT_EXPORT_PLUGIN_H diff --git a/platform/javascript/export/export_server.h b/platform/javascript/export/export_server.h index a831b76076..ddbe3cca30 100644 --- a/platform/javascript/export/export_server.h +++ b/platform/javascript/export/export_server.h @@ -35,7 +35,6 @@ #include "core/io/stream_peer_ssl.h" #include "core/io/tcp_server.h" #include "core/io/zip_io.h" -#include "editor/editor_export.h" #include "editor/editor_paths.h" class EditorHTTPServer : public RefCounted { @@ -248,4 +247,4 @@ public: } }; -#endif +#endif // JAVASCRIPT_EXPORT_SERVER_H diff --git a/platform/javascript/godot_audio.h b/platform/javascript/godot_audio.h index 012f8daeb7..3855b7301e 100644 --- a/platform/javascript/godot_audio.h +++ b/platform/javascript/godot_audio.h @@ -63,4 +63,4 @@ extern void godot_audio_script_start(float *p_in_buf, int p_in_size, float *p_ou } #endif -#endif /* GODOT_AUDIO_H */ +#endif // GODOT_AUDIO_H diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h index 1a383c9799..567b491336 100644 --- a/platform/javascript/godot_js.h +++ b/platform/javascript/godot_js.h @@ -127,4 +127,4 @@ extern void godot_js_display_vk_hide(); } #endif -#endif /* GODOT_JS_H */ +#endif // GODOT_JS_H diff --git a/platform/javascript/godot_webgl2.h b/platform/javascript/godot_webgl2.h index 7c357ff66d..968b70f84b 100644 --- a/platform/javascript/godot_webgl2.h +++ b/platform/javascript/godot_webgl2.h @@ -34,4 +34,4 @@ #include "GLES3/gl3.h" #include "webgl/webgl2.h" -#endif +#endif // GODOT_WEBGL2_H diff --git a/platform/javascript/http_client_javascript.h b/platform/javascript/http_client_javascript.h index 096aa6a153..fcd225ffc9 100644 --- a/platform/javascript/http_client_javascript.h +++ b/platform/javascript/http_client_javascript.h @@ -105,4 +105,5 @@ public: HTTPClientJavaScript(); ~HTTPClientJavaScript(); }; + #endif // HTTP_CLIENT_JAVASCRIPT_H diff --git a/platform/javascript/js/engine/config.js b/platform/javascript/js/engine/config.js index 2e5e1ed0d1..9c4b6c2012 100644 --- a/platform/javascript/js/engine/config.js +++ b/platform/javascript/js/engine/config.js @@ -334,6 +334,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- locale = navigator.languages ? navigator.languages[0] : navigator.language; locale = locale.split('.')[0]; } + locale = locale.replace('-', '_'); const onExit = this.onExit; // Godot configuration. diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 0c672111cc..6900a34ee3 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -107,4 +107,4 @@ public: OS_JavaScript(); }; -#endif +#endif // OS_JAVASCRIPT_H diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index 09a432eae2..636a3c7db2 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -12,7 +12,7 @@ common_linuxbsd = [ "freedesktop_screensaver.cpp", ] -if "x11" in env and env["x11"]: +if env["x11"]: common_linuxbsd += [ "gl_manager_x11.cpp", "detect_prime_x11.cpp", @@ -20,13 +20,13 @@ if "x11" in env and env["x11"]: "key_mapping_x11.cpp", ] -if "speechd" in env and env["speechd"]: - common_linuxbsd.append(["speechd-so_wrap.c", "tts_linux.cpp"]) + if env["vulkan"]: + common_linuxbsd.append("vulkan_context_x11.cpp") -if "vulkan" in env and env["vulkan"]: - common_linuxbsd.append("vulkan_context_x11.cpp") +if env["speechd"]: + common_linuxbsd.append(["speechd-so_wrap.c", "tts_linux.cpp"]) -if "udev" in env and env["udev"]: +if env["udev"]: common_linuxbsd.append("libudev-so_wrap.c") prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) diff --git a/platform/linuxbsd/crash_handler_linuxbsd.h b/platform/linuxbsd/crash_handler_linuxbsd.h index 2e44476c3f..1b77352cca 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.h +++ b/platform/linuxbsd/crash_handler_linuxbsd.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CRASH_HANDLER_X11_H -#define CRASH_HANDLER_X11_H +#ifndef CRASH_HANDLER_LINUXBSD_H +#define CRASH_HANDLER_LINUXBSD_H class CrashHandler { bool disabled; @@ -44,4 +44,4 @@ public: ~CrashHandler(); }; -#endif // CRASH_HANDLER_X11_H +#endif // CRASH_HANDLER_LINUXBSD_H diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 19cf341c85..065250c40e 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -1,6 +1,7 @@ import os import platform import sys +from methods import get_compiler_version, using_gcc def is_active(): @@ -15,47 +16,11 @@ def can_build(): if os.name != "posix" or sys.platform == "darwin": return False - # Check the minimal dependencies - x11_error = os.system("pkg-config --version > /dev/null") - if x11_error: + pkgconf_error = os.system("pkg-config --version > /dev/null") + if pkgconf_error: print("Error: pkg-config not found. Aborting.") return False - x11_error = os.system("pkg-config x11 --modversion > /dev/null") - if x11_error: - print("Error: X11 libraries not found. Aborting.") - return False - - x11_error = os.system("pkg-config xcursor --modversion > /dev/null") - if x11_error: - print("Error: Xcursor library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xinerama --modversion > /dev/null") - if x11_error: - print("Error: Xinerama library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xext --modversion > /dev/null") - if x11_error: - print("Error: Xext library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xrandr --modversion > /dev/null") - if x11_error: - print("Error: XrandR library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xrender --modversion > /dev/null") - if x11_error: - print("Error: XRender library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xi --modversion > /dev/null") - if x11_error: - print("Error: Xi library not found. Aborting.") - return False - return True @@ -63,9 +28,9 @@ def get_opts(): from SCons.Variables import BoolVariable, EnumVariable return [ + EnumVariable("linker", "Linker program", "default", ("default", "bfd", "gold", "lld", "mold")), BoolVariable("use_llvm", "Use the LLVM compiler", False), - BoolVariable("use_lld", "Use the LLD linker", False), - BoolVariable("use_thinlto", "Use ThinLTO", False), + BoolVariable("use_thinlto", "Use ThinLTO (LLVM only, requires linker=lld, implies use_lto=yes)", False), BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True), BoolVariable("use_coverage", "Test Godot coverage", False), BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), @@ -147,15 +112,32 @@ def configure(env): env["CXX"] = "clang++" env.extra_suffix = ".llvm" + env.extra_suffix - if env["use_lld"]: - if env["use_llvm"]: - env.Append(LINKFLAGS=["-fuse-ld=lld"]) - if env["use_thinlto"]: - # A convenience so you don't need to write use_lto too when using SCons - env["use_lto"] = True + if env["linker"] != "default": + print("Using linker program: " + env["linker"]) + if env["linker"] == "mold" and using_gcc(env): # GCC < 12.1 doesn't support -fuse-ld=mold. + cc_version = get_compiler_version(env) + cc_semver = (int(cc_version["major"]), int(cc_version["minor"])) + if cc_semver < (12, 1): + found_wrapper = False + for path in ["/usr/libexec", "/usr/local/libexec", "/usr/lib", "/usr/local/lib"]: + if os.path.isfile(path + "/mold/ld"): + env.Append(LINKFLAGS=["-B" + path + "/mold"]) + found_wrapper = True + break + if not found_wrapper: + print("Couldn't locate mold installation path. Make sure it's installed in /usr or /usr/local.") + sys.exit(255) + else: + env.Append(LINKFLAGS=["-fuse-ld=mold"]) else: - print("Using LLD with GCC is not supported yet. Try compiling with 'use_llvm=yes'.") + env.Append(LINKFLAGS=["-fuse-ld=%s" % env["linker"]]) + + if env["use_thinlto"]: + if not env["use_llvm"] or env["linker"] != "lld": + print("ThinLTO is only compatible with LLVM and the LLD linker, use `use_llvm=yes linker=lld`.") sys.exit(255) + else: + env["use_lto"] = True # ThinLTO implies LTO if env["use_coverage"]: env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"]) @@ -200,33 +182,32 @@ def configure(env): env.Append(LINKFLAGS=["-fsanitize=memory"]) if env["use_lto"]: - if not env["use_llvm"] and env.GetOption("num_jobs") > 1: + if env["use_thinlto"]: + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + elif not env["use_llvm"] and env.GetOption("num_jobs") > 1: env.Append(CCFLAGS=["-flto"]) env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))]) else: - if env["use_lld"] and env["use_thinlto"]: - env.Append(CCFLAGS=["-flto=thin"]) - env.Append(LINKFLAGS=["-flto=thin"]) - else: - env.Append(CCFLAGS=["-flto"]) - env.Append(LINKFLAGS=["-flto"]) + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) if not env["use_llvm"]: env["RANLIB"] = "gcc-ranlib" env["AR"] = "gcc-ar" env.Append(CCFLAGS=["-pipe"]) - env.Append(LINKFLAGS=["-pipe"]) ## Dependencies - env.ParseConfig("pkg-config x11 --cflags --libs") - env.ParseConfig("pkg-config xcursor --cflags --libs") - env.ParseConfig("pkg-config xinerama --cflags --libs") - env.ParseConfig("pkg-config xext --cflags --libs") - env.ParseConfig("pkg-config xrandr --cflags --libs") - env.ParseConfig("pkg-config xrender --cflags --libs") - env.ParseConfig("pkg-config xi --cflags --libs") + if env["x11"]: + env.ParseConfig("pkg-config x11 --cflags --libs") + env.ParseConfig("pkg-config xcursor --cflags --libs") + env.ParseConfig("pkg-config xinerama --cflags --libs") + env.ParseConfig("pkg-config xext --cflags --libs") + env.ParseConfig("pkg-config xrandr --cflags --libs") + env.ParseConfig("pkg-config xrender --cflags --libs") + env.ParseConfig("pkg-config xi --cflags --libs") if env["touch"]: env.Append(CPPDEFINES=["TOUCH_ENABLED"]) @@ -382,8 +363,9 @@ def configure(env): # No pkgconfig file so far, hardcode expected lib name. env.Append(LIBS=["glslang", "SPIRV"]) - env.Append(CPPDEFINES=["GLES3_ENABLED"]) - env.ParseConfig("pkg-config gl --cflags --libs") + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES3_ENABLED"]) + env.ParseConfig("pkg-config gl --cflags --libs") env.Append(LIBS=["pthread"]) diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h index e60f9ebfdf..21ebaead32 100644 --- a/platform/linuxbsd/detect_prime_x11.h +++ b/platform/linuxbsd/detect_prime_x11.h @@ -34,4 +34,5 @@ int detect_prime(); #endif -#endif + +#endif // DETECT_PRIME_X11_H diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 4aec111022..d4267d3c02 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -196,6 +196,7 @@ bool DisplayServerX11::_refresh_device_info() { xi.absolute_devices.clear(); xi.touch_devices.clear(); + xi.pen_inverted_devices.clear(); int dev_count; XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count); @@ -205,7 +206,7 @@ bool DisplayServerX11::_refresh_device_info() { if (!dev->enabled) { continue; } - if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave)) { + if (!(dev->use == XISlavePointer || dev->use == XIFloatingSlave)) { continue; } @@ -274,6 +275,7 @@ bool DisplayServerX11::_refresh_device_info() { xi.pen_pressure_range[dev->deviceid] = Vector2(pressure_min, pressure_max); xi.pen_tilt_x_range[dev->deviceid] = Vector2(tilt_x_min, tilt_x_max); xi.pen_tilt_y_range[dev->deviceid] = Vector2(tilt_y_min, tilt_y_max); + xi.pen_inverted_devices[dev->deviceid] = String(dev->name).findn("eraser") > 0; } XIFreeDeviceInfo(info); @@ -1487,8 +1489,8 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window XMoveResizeWindow(x11_display, wd.x11_window, position.x, position.y, size.x, size.y); } else { if (p_screen != window_get_current_screen(p_window)) { - Point2i position = screen_get_position(p_screen); - XMoveWindow(x11_display, wd.x11_window, position.x, position.y); + Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); + window_set_position(ofs + screen_get_position(p_screen), p_window); } } } @@ -1817,6 +1819,52 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a return retval; } +bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const { + ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; + + // Using EWMH -- Extended Window Manager Hints + Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False); + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = nullptr; + bool retval = false; + + if (property == None) { + return retval; + } + + int result = XGetWindowProperty( + x11_display, + wd.x11_window, + property, + 0, + 1024, + False, + XA_ATOM, + &type, + &format, + &len, + &remaining, + &data); + + if (result == Success) { + Atom *atoms = (Atom *)data; + Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False); + for (uint64_t i = 0; i < len; i++) { + if (atoms[i] == wm_fullscreen) { + retval = true; + break; + } + } + XFree(data); + } + + return retval; +} + bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const { _THREAD_SAFE_METHOD_ return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS"); @@ -3438,7 +3486,7 @@ void DisplayServerX11::process_events() { } break; case XI_RawMotion: { XIRawEvent *raw_event = (XIRawEvent *)event_data; - int device_id = raw_event->deviceid; + int device_id = raw_event->sourceid; // Determine the axis used (called valuators in XInput for some forsaken reason) // Mask is a bitmask indicating which axes are involved. @@ -3504,6 +3552,11 @@ void DisplayServerX11::process_events() { values++; } + HashMap<int, bool>::Iterator pen_inverted = xi.pen_inverted_devices.find(device_id); + if (pen_inverted) { + xi.pen_inverted = pen_inverted->value; + } + // https://bugs.freedesktop.org/show_bug.cgi?id=71609 // http://lists.libsdl.org/pipermail/commits-libsdl.org/2015-June/000282.html if (raw_event->time == xi.last_relative_time && rel_x == xi.relative_motion.x && rel_y == xi.relative_motion.y) { @@ -3604,6 +3657,8 @@ void DisplayServerX11::process_events() { case Expose: { DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count); + windows[window_id].fullscreen = _window_fullscreen_check(window_id); + Main::force_redraw(); } break; @@ -3936,6 +3991,7 @@ void DisplayServerX11::process_events() { mm->set_pressure(bool(mouse_get_button_state() & MouseButton::MASK_LEFT) ? 1.0f : 0.0f); } mm->set_tilt(xi.tilt); + mm->set_pen_inverted(xi.pen_inverted); _get_key_modifier_state(event.xmotion.state, mm); mm->set_button_mask((MouseButton)mouse_get_button_state()); @@ -4119,13 +4175,17 @@ void DisplayServerX11::process_events() { void DisplayServerX11::release_rendering_thread() { #if defined(GLES3_ENABLED) - gl_manager->release_current(); + if (gl_manager) { + gl_manager->release_current(); + } #endif } void DisplayServerX11::make_rendering_thread() { #if defined(GLES3_ENABLED) - gl_manager->make_current(); + if (gl_manager) { + gl_manager->make_current(); + } #endif } diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 4beeddd3a8..9ce6a557db 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -201,10 +201,12 @@ class DisplayServerX11 : public DisplayServer { HashMap<int, Vector2> pen_pressure_range; HashMap<int, Vector2> pen_tilt_x_range; HashMap<int, Vector2> pen_tilt_y_range; + HashMap<int, bool> pen_inverted_devices; XIEventMask all_event_mask; HashMap<int, Vector2> state; double pressure; bool pressure_supported; + bool pen_inverted; Vector2 tilt; Vector2 mouse_pos_to_filter; Vector2 relative_motion; @@ -265,6 +267,7 @@ class DisplayServerX11 : public DisplayServer { void _update_real_mouse_position(const WindowData &wd); bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const; + bool _window_fullscreen_check(WindowID p_window) const; void _update_size_hints(WindowID p_window); void _set_wm_fullscreen(WindowID p_window, bool p_enabled); void _set_wm_maximized(WindowID p_window, bool p_enabled); diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index 965b969ba8..bc1235bcec 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -30,17 +30,13 @@ #include "export.h" +#include "editor/export/editor_export.h" #include "export_plugin.h" void register_linuxbsd_exporter() { Ref<EditorExportPlatformLinuxBSD> platform; platform.instantiate(); - - Ref<Image> img = memnew(Image(_linuxbsd_logo)); - Ref<ImageTexture> logo; - logo.instantiate(); - logo->create_from_image(img); - platform->set_logo(logo); + platform->set_logo(ImageTexture::create_from_image(memnew(Image(_linuxbsd_logo)))); platform->set_name("Linux/X11"); platform->set_extension("x86_32"); platform->set_extension("x86_64", "binary_format/64_bits"); diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp index 4e14920e79..d54e07d8a5 100644 --- a/platform/linuxbsd/export/export_plugin.cpp +++ b/platform/linuxbsd/export/export_plugin.cpp @@ -84,7 +84,7 @@ void EditorExportPlatformLinuxBSD::set_extension(const String &p_extension, cons } String EditorExportPlatformLinuxBSD::get_template_file_name(const String &p_target, const String &p_arch) const { - return "linux_x11_" + p_arch + "_" + p_target; + return "linux_" + p_target + "." + p_arch; } List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h index e04bcc20f9..98e4616035 100644 --- a/platform/linuxbsd/export/export_plugin.h +++ b/platform/linuxbsd/export/export_plugin.h @@ -32,8 +32,8 @@ #define LINUXBSD_EXPORT_PLUGIN_H #include "core/io/file_access.h" -#include "editor/editor_export.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export_platform_pc.h" #include "platform/linuxbsd/logo.gen.h" #include "scene/resources/texture.h" @@ -49,4 +49,4 @@ public: virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; }; -#endif +#endif // LINUXBSD_EXPORT_PLUGIN_H diff --git a/platform/linuxbsd/freedesktop_screensaver.h b/platform/linuxbsd/freedesktop_screensaver.h index b2303791bd..1b632b9103 100644 --- a/platform/linuxbsd/freedesktop_screensaver.h +++ b/platform/linuxbsd/freedesktop_screensaver.h @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef FREEDESKTOP_SCREENSAVER_H +#define FREEDESKTOP_SCREENSAVER_H + #ifdef DBUS_ENABLED #include <dbus/dbus.h> @@ -45,3 +48,5 @@ public: }; #endif // DBUS_ENABLED + +#endif // FREEDESKTOP_SCREENSAVER_H diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp index 9fe00568fb..91a260182e 100644 --- a/platform/linuxbsd/godot_linuxbsd.cpp +++ b/platform/linuxbsd/godot_linuxbsd.cpp @@ -61,6 +61,10 @@ int main(int argc, char *argv[]) { Error err = Main::setup(argv[0], argc - 1, &argv[1]); if (err != OK) { free(cwd); + + if (err == ERR_HELP) { // Returned by --help and --version, so success. + return 0; + } return 255; } diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index 3f97b86eae..13c07842fb 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -105,4 +105,4 @@ public: OS_LinuxBSD(); }; -#endif +#endif // OS_LINUXBSD_H diff --git a/platform/linuxbsd/vulkan_context_x11.h b/platform/linuxbsd/vulkan_context_x11.h index a89afa2eff..0c4a6cd278 100644 --- a/platform/linuxbsd/vulkan_context_x11.h +++ b/platform/linuxbsd/vulkan_context_x11.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VULKAN_DEVICE_X11_H -#define VULKAN_DEVICE_X11_H +#ifndef VULKAN_CONTEXT_X11_H +#define VULKAN_CONTEXT_X11_H #include "drivers/vulkan/vulkan_context.h" #include <X11/Xlib.h> @@ -44,4 +44,4 @@ public: ~VulkanContextX11(); }; -#endif // VULKAN_DEVICE_X11_H +#endif // VULKAN_CONTEXT_X11_H diff --git a/platform/macos/SCsub b/platform/macos/SCsub new file mode 100644 index 0000000000..d0856c709a --- /dev/null +++ b/platform/macos/SCsub @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +Import("env") + +from platform_methods import run_in_subprocess +import platform_macos_builders + +files = [ + "os_macos.mm", + "godot_application.mm", + "godot_application_delegate.mm", + "crash_handler_macos.mm", + "macos_terminal_logger.mm", + "display_server_macos.mm", + "godot_content_view.mm", + "godot_window_delegate.mm", + "godot_window.mm", + "key_mapping_macos.mm", + "godot_main_macos.mm", + "dir_access_macos.mm", + "tts_macos.mm", + "joypad_macos.cpp", + "vulkan_context_macos.mm", + "gl_manager_macos_legacy.mm", +] + +prog = env.add_program("#bin/godot", files) + +if env["debug_symbols"] and env["separate_debug_symbols"]: + env.AddPostAction(prog, run_in_subprocess(platform_macos_builders.make_debug_macos)) diff --git a/platform/osx/crash_handler_osx.h b/platform/macos/crash_handler_macos.h index 72938e5e0a..c9b0e77dc4 100644 --- a/platform/osx/crash_handler_osx.h +++ b/platform/macos/crash_handler_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* crash_handler_osx.h */ +/* crash_handler_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CRASH_HANDLER_OSX_H -#define CRASH_HANDLER_OSX_H +#ifndef CRASH_HANDLER_MACOS_H +#define CRASH_HANDLER_MACOS_H class CrashHandler { bool disabled; @@ -44,4 +44,4 @@ public: ~CrashHandler(); }; -#endif // CRASH_HANDLER_OSX_H +#endif // CRASH_HANDLER_MACOS_H diff --git a/platform/osx/crash_handler_osx.mm b/platform/macos/crash_handler_macos.mm index a798ba3b46..74bd012f0c 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/macos/crash_handler_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* crash_handler_osx.mm */ +/* crash_handler_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "crash_handler_osx.h" +#include "crash_handler_macos.h" #include "core/config/project_settings.h" #include "core/os/os.h" diff --git a/platform/osx/detect.py b/platform/macos/detect.py index 8d848d2094..20e7afa772 100644 --- a/platform/osx/detect.py +++ b/platform/macos/detect.py @@ -8,7 +8,7 @@ def is_active(): def get_name(): - return "OSX" + return "macOS" def can_build(): @@ -24,7 +24,7 @@ def get_opts(): return [ ("osxcross_sdk", "OSXCross SDK version", "darwin16"), ("MACOS_SDK_PATH", "Path to the macOS SDK", ""), - ("VULKAN_SDK_PATH", "Path to the Vulkan SDK", ""), + ("vulkan_sdk_path", "Path to the Vulkan SDK", ""), EnumVariable("macports_clang", "Build using Clang from MacPorts", "no", ("no", "5.0", "devel")), BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False), @@ -36,7 +36,38 @@ def get_opts(): def get_flags(): - return [] + return [ + ("use_volk", False), + ] + + +def get_mvk_sdk_path(): + def int_or_zero(i): + try: + return int(i) + except: + return 0 + + def ver_parse(a): + return [int_or_zero(i) for i in a.split(".")] + + dirname = os.path.expanduser("~/VulkanSDK") + files = os.listdir(dirname) + + ver_file = "0.0.0.0" + ver_num = ver_parse(ver_file) + + for file in files: + if os.path.isdir(os.path.join(dirname, file)): + ver_comp = ver_parse(file) + lib_name = os.path.join( + os.path.join(dirname, file), "MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/libMoltenVK.a" + ) + if os.path.isfile(lib_name) and ver_comp > ver_num: + ver_num = ver_comp + ver_file = file + + return os.path.join(os.path.join(dirname, ver_file), "MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/") def configure(env): @@ -67,7 +98,7 @@ def configure(env): ## Architecture - # Mac OS X no longer runs on 32-bit since 10.7 which is unsupported since 2014 + # macOS no longer runs on 32-bit since 10.7 which is unsupported since 2014 # As such, we only support 64-bit env["bits"] = "64" @@ -79,10 +110,12 @@ def configure(env): if env["arch"] == "arm64": print("Building for macOS 11.0+, platform arm64.") + env.Append(ASFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) env.Append(CCFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) env.Append(LINKFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) else: print("Building for macOS 10.12+, platform x86_64.") + env.Append(ASFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) env.Append(LINKFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) @@ -101,7 +134,7 @@ def configure(env): env["CC"] = "clang" env["CXX"] = "clang++" - detect_darwin_sdk_path("osx", env) + detect_darwin_sdk_path("macos", env) env.Append(CCFLAGS=["-isysroot", "$MACOS_SDK_PATH"]) env.Append(LINKFLAGS=["-isysroot", "$MACOS_SDK_PATH"]) @@ -158,8 +191,10 @@ def configure(env): ## Flags - env.Prepend(CPPPATH=["#platform/osx"]) - env.Append(CPPDEFINES=["OSX_ENABLED", "UNIX_ENABLED", "APPLE_STYLE_KEYS", "COREAUDIO_ENABLED", "COREMIDI_ENABLED"]) + env.Prepend(CPPPATH=["#platform/macos"]) + env.Append( + CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED", "APPLE_STYLE_KEYS", "COREAUDIO_ENABLED", "COREMIDI_ENABLED"] + ) env.Append( LINKFLAGS=[ "-framework", @@ -197,4 +232,22 @@ def configure(env): env.Append(CPPDEFINES=["VULKAN_ENABLED"]) env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "QuartzCore", "-framework", "IOSurface"]) if not env["use_volk"]: - env.Append(LINKFLAGS=["-L$VULKAN_SDK_PATH/MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/", "-lMoltenVK"]) + env.Append(LINKFLAGS=["-lMoltenVK"]) + mvk_found = False + if env["vulkan_sdk_path"] != "": + mvk_path = os.path.join( + os.path.expanduser(env["vulkan_sdk_path"]), "MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/" + ) + if os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")): + mvk_found = True + env.Append(LINKFLAGS=["-L" + mvk_path]) + if not mvk_found: + mvk_path = get_mvk_sdk_path() + if os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")): + mvk_found = True + env.Append(LINKFLAGS=["-L" + mvk_path]) + if not mvk_found: + print( + "MoltenVK SDK installation directory not found, use 'vulkan_sdk_path' SCons parameter to specify SDK path." + ) + sys.exit(255) diff --git a/platform/osx/dir_access_osx.h b/platform/macos/dir_access_macos.h index 3c66c81d4f..1ac1b995de 100644 --- a/platform/osx/dir_access_osx.h +++ b/platform/macos/dir_access_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* dir_access_osx.h */ +/* dir_access_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef DIR_ACCESS_OSX_H -#define DIR_ACCESS_OSX_H +#ifndef DIR_ACCESS_MACOS_H +#define DIR_ACCESS_MACOS_H #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) @@ -41,7 +41,7 @@ #include "core/io/dir_access.h" #include "drivers/unix/dir_access_unix.h" -class DirAccessOSX : public DirAccessUnix { +class DirAccessMacOS : public DirAccessUnix { protected: virtual String fix_unicode_name(const char *p_name) const; @@ -51,5 +51,6 @@ protected: virtual bool is_hidden(const String &p_name); }; -#endif //UNIX ENABLED -#endif +#endif // UNIX ENABLED || LIBC_FILEIO_ENABLED + +#endif // DIR_ACCESS_MACOS_H diff --git a/platform/osx/dir_access_osx.mm b/platform/macos/dir_access_macos.mm index 6bafb9470d..94d937a7dc 100644 --- a/platform/osx/dir_access_osx.mm +++ b/platform/macos/dir_access_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* dir_access_osx.mm */ +/* dir_access_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "dir_access_osx.h" +#include "dir_access_macos.h" #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) @@ -37,7 +37,7 @@ #import <AppKit/NSWorkspace.h> #import <Foundation/Foundation.h> -String DirAccessOSX::fix_unicode_name(const char *p_name) const { +String DirAccessMacOS::fix_unicode_name(const char *p_name) const { String fname; NSString *nsstr = [[NSString stringWithUTF8String:p_name] precomposedStringWithCanonicalMapping]; @@ -46,14 +46,14 @@ String DirAccessOSX::fix_unicode_name(const char *p_name) const { return fname; } -int DirAccessOSX::get_drive_count() { +int DirAccessMacOS::get_drive_count() { NSArray *res_keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsSystemImmutableKey, nil]; NSArray *vols = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:res_keys options:NSVolumeEnumerationSkipHiddenVolumes]; return [vols count]; } -String DirAccessOSX::get_drive(int p_drive) { +String DirAccessMacOS::get_drive(int p_drive) { NSArray *res_keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsSystemImmutableKey, nil]; NSArray *vols = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:res_keys options:NSVolumeEnumerationSkipHiddenVolumes]; int count = [vols count]; @@ -68,7 +68,7 @@ String DirAccessOSX::get_drive(int p_drive) { return volname; } -bool DirAccessOSX::is_hidden(const String &p_name) { +bool DirAccessMacOS::is_hidden(const String &p_name) { String f = get_current_dir().plus_file(p_name); NSURL *url = [NSURL fileURLWithPath:@(f.utf8().get_data())]; NSNumber *hidden = nil; @@ -78,4 +78,4 @@ bool DirAccessOSX::is_hidden(const String &p_name) { return [hidden boolValue]; } -#endif //posix_enabled +#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED diff --git a/platform/osx/display_server_osx.h b/platform/macos/display_server_macos.h index 9575cb29a2..41031ec81b 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/macos/display_server_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_osx.h */ +/* display_server_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef DISPLAY_SERVER_OSX_H -#define DISPLAY_SERVER_OSX_H +#ifndef DISPLAY_SERVER_MACOS_H +#define DISPLAY_SERVER_MACOS_H #define BitMap _QDBitMap // Suppress deprecated QuickDraw definition. @@ -37,12 +37,12 @@ #include "servers/display_server.h" #if defined(GLES3_ENABLED) -#include "gl_manager_osx_legacy.h" +#include "gl_manager_macos_legacy.h" #endif // GLES3_ENABLED #if defined(VULKAN_ENABLED) #include "drivers/vulkan/rendering_device_vulkan.h" -#include "platform/osx/vulkan_context_osx.h" +#include "platform/macos/vulkan_context_macos.h" #endif // VULKAN_ENABLED #import <AppKit/AppKit.h> @@ -54,15 +54,15 @@ #undef BitMap #undef CursorShape -class DisplayServerOSX : public DisplayServer { - GDCLASS(DisplayServerOSX, DisplayServer) +class DisplayServerMacOS : public DisplayServer { + GDCLASS(DisplayServerMacOS, DisplayServer) _THREAD_SAFE_CLASS_ public: struct KeyEvent { WindowID window_id = INVALID_WINDOW_ID; - unsigned int osx_state = false; + unsigned int macos_state = false; bool pressed = false; bool echo = false; bool raw = false; @@ -115,10 +115,10 @@ public: private: #if defined(GLES3_ENABLED) - GLManager_OSX *gl_manager = nullptr; + GLManager_MacOS *gl_manager = nullptr; #endif #if defined(VULKAN_ENABLED) - VulkanContextOSX *context_vulkan = nullptr; + VulkanContextMacOS *context_vulkan = nullptr; RenderingDeviceVulkan *rendering_device_vulkan = nullptr; #endif String rendering_driver; @@ -203,7 +203,7 @@ public: void send_event(NSEvent *p_event); void send_window_event(const WindowData &p_wd, WindowEvent p_event); void release_pressed_events(); - void get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) const; + void get_key_modifier_state(unsigned int p_macos_state, Ref<InputEventWithModifiers> r_state) const; void update_mouse_pos(WindowData &p_wd, NSPoint p_location_in_window); void push_to_key_event_buffer(const KeyEvent &p_event); void update_im_text(const Point2i &p_selection, const String &p_text); @@ -397,10 +397,10 @@ public: static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); - static void register_osx_driver(); + static void register_macos_driver(); - DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); - ~DisplayServerOSX(); + DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + ~DisplayServerMacOS(); }; -#endif // DISPLAY_SERVER_OSX_H +#endif // DISPLAY_SERVER_MACOS_H diff --git a/platform/osx/display_server_osx.mm b/platform/macos/display_server_macos.mm index b6a5813bd0..07ba5d7497 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/macos/display_server_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_osx.mm */ +/* display_server_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "display_server_osx.h" +#include "display_server_macos.h" #include "godot_content_view.h" #include "godot_menu_item.h" #include "godot_window.h" #include "godot_window_delegate.h" -#include "key_mapping_osx.h" -#include "os_osx.h" +#include "key_mapping_macos.h" +#include "os_macos.h" -#include "tts_osx.h" +#include "tts_macos.h" #include "core/io/marshalls.h" #include "core/math/geometry_2d.h" @@ -60,7 +60,7 @@ #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #endif -const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const { +const NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) const { const NSMenu *menu = nullptr; if (p_menu_root == "") { // Main menu. @@ -81,7 +81,7 @@ const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const return menu; } -NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) { +NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) { NSMenu *menu = nullptr; if (p_menu_root == "") { // Main menu. @@ -105,7 +105,7 @@ NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) { return menu; } -DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) { +DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) { WindowID id; const float scale = screen_get_max_scale(); { @@ -193,7 +193,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V return id; } -void DisplayServerOSX::_update_window_style(WindowData p_wd) { +void DisplayServerMacOS::_update_window_style(WindowData p_wd) { bool borderless_full = false; if (p_wd.borderless) { @@ -222,7 +222,7 @@ void DisplayServerOSX::_update_window_style(WindowData p_wd) { } } -void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window) { +void DisplayServerMacOS::_set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; @@ -267,7 +267,7 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled } } -void DisplayServerOSX::_update_displays_arrangement() { +void DisplayServerMacOS::_update_displays_arrangement() { origin = Point2i(); for (int i = 0; i < get_screen_count(); i++) { @@ -282,20 +282,20 @@ void DisplayServerOSX::_update_displays_arrangement() { displays_arrangement_dirty = false; } -Point2i DisplayServerOSX::_get_screens_origin() const { +Point2i DisplayServerMacOS::_get_screens_origin() const { // Returns the native top-left screen coordinate of the smallest rectangle // that encompasses all screens. Needed in get_screen_position(), // window_get_position, and window_set_position() // to convert between OS X native screen coordinates and the ones expected by Godot. if (displays_arrangement_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_displays_arrangement(); + const_cast<DisplayServerMacOS *>(this)->_update_displays_arrangement(); } return origin; } -Point2i DisplayServerOSX::_get_native_screen_position(int p_screen) const { +Point2i DisplayServerMacOS::_get_native_screen_position(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if ((NSUInteger)p_screen < [screenArray count]) { NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame]; @@ -306,18 +306,18 @@ Point2i DisplayServerOSX::_get_native_screen_position(int p_screen) const { return Point2i(); } -void DisplayServerOSX::_displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); +void DisplayServerMacOS::_displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->displays_arrangement_dirty = true; } } -void DisplayServerOSX::_dispatch_input_events(const Ref<InputEvent> &p_event) { - ((DisplayServerOSX *)(get_singleton()))->_dispatch_input_event(p_event); +void DisplayServerMacOS::_dispatch_input_events(const Ref<InputEvent> &p_event) { + ((DisplayServerMacOS *)(get_singleton()))->_dispatch_input_event(p_event); } -void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { +void DisplayServerMacOS::_dispatch_input_event(const Ref<InputEvent> &p_event) { _THREAD_SAFE_METHOD_ if (!in_dispatch_input_event) { in_dispatch_input_event = true; @@ -364,12 +364,12 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { } } -void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) { +void DisplayServerMacOS::_push_input(const Ref<InputEvent> &p_event) { Ref<InputEvent> ev = p_event; Input::get_singleton()->parse_input_event(ev); } -void DisplayServerOSX::_process_key_events() { +void DisplayServerMacOS::_process_key_events() { Ref<InputEventKey> k; for (int i = 0; i < key_event_pos; i++) { const KeyEvent &ke = key_event_buffer[i]; @@ -378,7 +378,7 @@ void DisplayServerOSX::_process_key_events() { k.instantiate(); k->set_window_id(ke.window_id); - get_key_modifier_state(ke.osx_state, k); + get_key_modifier_state(ke.macos_state, k); k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_keycode(ke.keycode); @@ -392,7 +392,7 @@ void DisplayServerOSX::_process_key_events() { k.instantiate(); k->set_window_id(ke.window_id); - get_key_modifier_state(ke.osx_state, k); + get_key_modifier_state(ke.macos_state, k); k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_keycode(Key::NONE); @@ -405,7 +405,7 @@ void DisplayServerOSX::_process_key_events() { k.instantiate(); k->set_window_id(ke.window_id); - get_key_modifier_state(ke.osx_state, k); + get_key_modifier_state(ke.macos_state, k); k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_keycode(ke.keycode); @@ -423,7 +423,7 @@ void DisplayServerOSX::_process_key_events() { key_event_pos = 0; } -void DisplayServerOSX::_update_keyboard_layouts() { +void DisplayServerMacOS::_update_keyboard_layouts() { kbd_layouts.clear(); current_layout = 0; @@ -468,14 +468,14 @@ void DisplayServerOSX::_update_keyboard_layouts() { keyboard_layout_dirty = false; } -void DisplayServerOSX::_keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); +void DisplayServerMacOS::_keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->keyboard_layout_dirty = true; } } -NSImage *DisplayServerOSX::_convert_to_nsimg(Ref<Image> &p_image) const { +NSImage *DisplayServerMacOS::_convert_to_nsimg(Ref<Image> &p_image) const { p_image->convert(Image::FORMAT_RGBA8); NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL @@ -509,7 +509,7 @@ NSImage *DisplayServerOSX::_convert_to_nsimg(Ref<Image> &p_image) const { return nsimg; } -NSCursor *DisplayServerOSX::_cursor_from_selector(SEL p_selector, SEL p_fallback) { +NSCursor *DisplayServerMacOS::_cursor_from_selector(SEL p_selector, SEL p_fallback) { if ([NSCursor respondsToSelector:p_selector]) { id object = [NSCursor performSelector:p_selector]; if ([object isKindOfClass:[NSCursor class]]) { @@ -523,11 +523,11 @@ NSCursor *DisplayServerOSX::_cursor_from_selector(SEL p_selector, SEL p_fallback return [NSCursor arrowCursor]; } -NSMenu *DisplayServerOSX::get_dock_menu() const { +NSMenu *DisplayServerMacOS::get_dock_menu() const { return dock_menu; } -void DisplayServerOSX::menu_callback(id p_sender) { +void DisplayServerMacOS::menu_callback(id p_sender) { if (![p_sender representedObject]) { return; } @@ -560,15 +560,15 @@ void DisplayServerOSX::menu_callback(id p_sender) { } } -bool DisplayServerOSX::has_window(WindowID p_window) const { +bool DisplayServerMacOS::has_window(WindowID p_window) const { return windows.has(p_window); } -DisplayServerOSX::WindowData &DisplayServerOSX::get_window(WindowID p_window) { +DisplayServerMacOS::WindowData &DisplayServerMacOS::get_window(WindowID p_window) { return windows[p_window]; } -void DisplayServerOSX::send_event(NSEvent *p_event) { +void DisplayServerMacOS::send_event(NSEvent *p_event) { // Special case handling of command-period, which is traditionally a special // shortcut in macOS and doesn't arrive at our regular keyDown handler. if ([p_event type] == NSEventTypeKeyDown) { @@ -577,7 +577,7 @@ void DisplayServerOSX::send_event(NSEvent *p_event) { k.instantiate(); get_key_modifier_state([p_event modifierFlags], k); - k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID); + k->set_window_id(DisplayServerMacOS::INVALID_WINDOW_ID); k->set_pressed(true); k->set_keycode(Key::PERIOD); k->set_physical_keycode(Key::PERIOD); @@ -588,7 +588,7 @@ void DisplayServerOSX::send_event(NSEvent *p_event) { } } -void DisplayServerOSX::send_window_event(const WindowData &wd, WindowEvent p_event) { +void DisplayServerMacOS::send_window_event(const WindowData &wd, WindowEvent p_event) { _THREAD_SAFE_METHOD_ if (!wd.event_callback.is_null()) { @@ -600,21 +600,21 @@ void DisplayServerOSX::send_window_event(const WindowData &wd, WindowEvent p_eve } } -void DisplayServerOSX::release_pressed_events() { +void DisplayServerMacOS::release_pressed_events() { _THREAD_SAFE_METHOD_ if (Input::get_singleton()) { Input::get_singleton()->release_pressed_events(); } } -void DisplayServerOSX::get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) const { - r_state->set_shift_pressed((p_osx_state & NSEventModifierFlagShift)); - r_state->set_ctrl_pressed((p_osx_state & NSEventModifierFlagControl)); - r_state->set_alt_pressed((p_osx_state & NSEventModifierFlagOption)); - r_state->set_meta_pressed((p_osx_state & NSEventModifierFlagCommand)); +void DisplayServerMacOS::get_key_modifier_state(unsigned int p_macos_state, Ref<InputEventWithModifiers> r_state) const { + r_state->set_shift_pressed((p_macos_state & NSEventModifierFlagShift)); + r_state->set_ctrl_pressed((p_macos_state & NSEventModifierFlagControl)); + r_state->set_alt_pressed((p_macos_state & NSEventModifierFlagOption)); + r_state->set_meta_pressed((p_macos_state & NSEventModifierFlagCommand)); } -void DisplayServerOSX::update_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPoint p_location_in_window) { +void DisplayServerMacOS::update_mouse_pos(DisplayServerMacOS::WindowData &p_wd, NSPoint p_location_in_window) { const NSRect content_rect = [p_wd.window_view frame]; const float scale = screen_get_max_scale(); p_wd.mouse_pos.x = p_location_in_window.x * scale; @@ -622,33 +622,33 @@ void DisplayServerOSX::update_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPo Input::get_singleton()->set_mouse_position(p_wd.mouse_pos); } -void DisplayServerOSX::push_to_key_event_buffer(const DisplayServerOSX::KeyEvent &p_event) { +void DisplayServerMacOS::push_to_key_event_buffer(const DisplayServerMacOS::KeyEvent &p_event) { if (key_event_pos >= key_event_buffer.size()) { key_event_buffer.resize(1 + key_event_pos); } key_event_buffer.write[key_event_pos++] = p_event; } -void DisplayServerOSX::update_im_text(const Point2i &p_selection, const String &p_text) { +void DisplayServerMacOS::update_im_text(const Point2i &p_selection, const String &p_text) { im_selection = p_selection; im_text = p_text; OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE); } -void DisplayServerOSX::set_last_focused_window(WindowID p_window) { +void DisplayServerMacOS::set_last_focused_window(WindowID p_window) { last_focused_window = p_window; } -void DisplayServerOSX::set_is_resizing(bool p_is_resizing) { +void DisplayServerMacOS::set_is_resizing(bool p_is_resizing) { is_resizing = p_is_resizing; } -bool DisplayServerOSX::get_is_resizing() const { +bool DisplayServerMacOS::get_is_resizing() const { return is_resizing; } -void DisplayServerOSX::window_update(WindowID p_window) { +void DisplayServerMacOS::window_update(WindowID p_window) { #if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->window_update(p_window); @@ -656,7 +656,7 @@ void DisplayServerOSX::window_update(WindowID p_window) { #endif } -void DisplayServerOSX::window_destroy(WindowID p_window) { +void DisplayServerMacOS::window_destroy(WindowID p_window) { #if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->window_destroy(p_window); @@ -670,7 +670,7 @@ void DisplayServerOSX::window_destroy(WindowID p_window) { windows.erase(p_window); } -void DisplayServerOSX::window_resize(WindowID p_window, int p_width, int p_height) { +void DisplayServerMacOS::window_resize(WindowID p_window, int p_width, int p_height) { #if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->window_resize(p_window, p_width, p_height); @@ -683,7 +683,7 @@ void DisplayServerOSX::window_resize(WindowID p_window, int p_width, int p_heigh #endif } -bool DisplayServerOSX::has_feature(Feature p_feature) const { +bool DisplayServerMacOS::has_feature(Feature p_feature) const { switch (p_feature) { case FEATURE_GLOBAL_MENU: case FEATURE_SUBWINDOWS: @@ -709,16 +709,16 @@ bool DisplayServerOSX::has_feature(Feature p_feature) const { return false; } -String DisplayServerOSX::get_name() const { - return "OSX"; +String DisplayServerMacOS::get_name() const { + return "macOS"; } -void DisplayServerOSX::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +void DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); + String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); NSMenuItem *menu_item; if (p_index != -1) { menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; @@ -731,17 +731,17 @@ void DisplayServerOSX::global_menu_add_item(const String &p_menu_root, const Str obj->checkable_type = CHECKABLE_TYPE_NONE; obj->max_states = 0; obj->state = 0; - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } } -void DisplayServerOSX::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +void DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); + String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); NSMenuItem *menu_item; if (p_index != -1) { menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; @@ -754,17 +754,17 @@ void DisplayServerOSX::global_menu_add_check_item(const String &p_menu_root, con obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX; obj->max_states = 0; obj->state = 0; - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } } -void DisplayServerOSX::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +void DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); + String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); NSMenuItem *menu_item; if (p_index != -1) { menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; @@ -786,17 +786,17 @@ void DisplayServerOSX::global_menu_add_icon_item(const String &p_menu_root, cons obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS); [menu_item setImage:_convert_to_nsimg(obj->img)]; } - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } } -void DisplayServerOSX::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +void DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); + String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); NSMenuItem *menu_item; if (p_index != -1) { menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; @@ -818,17 +818,17 @@ void DisplayServerOSX::global_menu_add_icon_check_item(const String &p_menu_root obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS); [menu_item setImage:_convert_to_nsimg(obj->img)]; } - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } } -void DisplayServerOSX::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +void DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); + String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); NSMenuItem *menu_item; if (p_index != -1) { menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; @@ -841,17 +841,17 @@ void DisplayServerOSX::global_menu_add_radio_check_item(const String &p_menu_roo obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON; obj->max_states = 0; obj->state = 0; - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } } -void DisplayServerOSX::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +void DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); + String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); NSMenuItem *menu_item; if (p_index != -1) { menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; @@ -873,17 +873,17 @@ void DisplayServerOSX::global_menu_add_icon_radio_check_item(const String &p_men obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS); [menu_item setImage:_convert_to_nsimg(obj->img)]; } - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } } -void DisplayServerOSX::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +void DisplayServerMacOS::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); + String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); NSMenuItem *menu_item; if (p_index != -1) { menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; @@ -896,12 +896,12 @@ void DisplayServerOSX::global_menu_add_multistate_item(const String &p_menu_root obj->checkable_type = CHECKABLE_TYPE_NONE; obj->max_states = p_max_states; obj->state = p_default_state; - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } } -void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) { +void DisplayServerMacOS::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -926,7 +926,7 @@ void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, c } } -void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root, int p_index) { +void DisplayServerMacOS::global_menu_add_separator(const String &p_menu_root, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -939,7 +939,7 @@ void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root, int } } -int DisplayServerOSX::global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const { +int DisplayServerMacOS::global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -950,7 +950,7 @@ int DisplayServerOSX::global_menu_get_item_index_from_text(const String &p_menu_ return -1; } -int DisplayServerOSX::global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const { +int DisplayServerMacOS::global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -969,7 +969,7 @@ int DisplayServerOSX::global_menu_get_item_index_from_tag(const String &p_menu_r return -1; } -bool DisplayServerOSX::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const { +bool DisplayServerMacOS::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -982,7 +982,7 @@ bool DisplayServerOSX::global_menu_is_item_checked(const String &p_menu_root, in return false; } -bool DisplayServerOSX::global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const { +bool DisplayServerMacOS::global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -998,7 +998,7 @@ bool DisplayServerOSX::global_menu_is_item_checkable(const String &p_menu_root, return false; } -bool DisplayServerOSX::global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const { +bool DisplayServerMacOS::global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1014,7 +1014,7 @@ bool DisplayServerOSX::global_menu_is_item_radio_checkable(const String &p_menu_ return false; } -Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_root, int p_idx) const { +Callable DisplayServerMacOS::global_menu_get_item_callback(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1030,7 +1030,7 @@ Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_ro return Callable(); } -Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const { +Variant DisplayServerMacOS::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1046,7 +1046,7 @@ Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, in return Variant(); } -String DisplayServerOSX::global_menu_get_item_text(const String &p_menu_root, int p_idx) const { +String DisplayServerMacOS::global_menu_get_item_text(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1059,7 +1059,7 @@ String DisplayServerOSX::global_menu_get_item_text(const String &p_menu_root, in return String(); } -String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const { +String DisplayServerMacOS::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1079,7 +1079,7 @@ String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, return String(); } -Key DisplayServerOSX::global_menu_get_item_accelerator(const String &p_menu_root, int p_idx) const { +Key DisplayServerMacOS::global_menu_get_item_accelerator(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1110,7 +1110,7 @@ Key DisplayServerOSX::global_menu_get_item_accelerator(const String &p_menu_root return Key::NONE; } -bool DisplayServerOSX::global_menu_is_item_disabled(const String &p_menu_root, int p_idx) const { +bool DisplayServerMacOS::global_menu_is_item_disabled(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1123,7 +1123,7 @@ bool DisplayServerOSX::global_menu_is_item_disabled(const String &p_menu_root, i return false; } -String DisplayServerOSX::global_menu_get_item_tooltip(const String &p_menu_root, int p_idx) const { +String DisplayServerMacOS::global_menu_get_item_tooltip(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1136,7 +1136,7 @@ String DisplayServerOSX::global_menu_get_item_tooltip(const String &p_menu_root, return String(); } -int DisplayServerOSX::global_menu_get_item_state(const String &p_menu_root, int p_idx) const { +int DisplayServerMacOS::global_menu_get_item_state(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1152,7 +1152,7 @@ int DisplayServerOSX::global_menu_get_item_state(const String &p_menu_root, int return 0; } -int DisplayServerOSX::global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const { +int DisplayServerMacOS::global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1168,7 +1168,7 @@ int DisplayServerOSX::global_menu_get_item_max_states(const String &p_menu_root, return 0; } -Ref<Texture2D> DisplayServerOSX::global_menu_get_item_icon(const String &p_menu_root, int p_idx) const { +Ref<Texture2D> DisplayServerMacOS::global_menu_get_item_icon(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1178,10 +1178,7 @@ Ref<Texture2D> DisplayServerOSX::global_menu_get_item_icon(const String &p_menu_ GodotMenuItem *obj = [menu_item representedObject]; if (obj) { if (obj->img.is_valid()) { - Ref<ImageTexture> txt; - txt.instantiate(); - txt->create_from_image(obj->img); - return txt; + return ImageTexture::create_from_image(obj->img); } } } @@ -1189,7 +1186,7 @@ Ref<Texture2D> DisplayServerOSX::global_menu_get_item_icon(const String &p_menu_ return Ref<Texture2D>(); } -void DisplayServerOSX::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) { +void DisplayServerMacOS::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1208,7 +1205,7 @@ void DisplayServerOSX::global_menu_set_item_checked(const String &p_menu_root, i } } -void DisplayServerOSX::global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { +void DisplayServerMacOS::global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1224,7 +1221,7 @@ void DisplayServerOSX::global_menu_set_item_checkable(const String &p_menu_root, } } -void DisplayServerOSX::global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { +void DisplayServerMacOS::global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1240,7 +1237,7 @@ void DisplayServerOSX::global_menu_set_item_radio_checkable(const String &p_menu } } -void DisplayServerOSX::global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) { +void DisplayServerMacOS::global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1256,7 +1253,7 @@ void DisplayServerOSX::global_menu_set_item_callback(const String &p_menu_root, } } -void DisplayServerOSX::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) { +void DisplayServerMacOS::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1272,7 +1269,7 @@ void DisplayServerOSX::global_menu_set_item_tag(const String &p_menu_root, int p } } -void DisplayServerOSX::global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) { +void DisplayServerMacOS::global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1287,7 +1284,7 @@ void DisplayServerOSX::global_menu_set_item_text(const String &p_menu_root, int } } -void DisplayServerOSX::global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) { +void DisplayServerMacOS::global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1311,7 +1308,7 @@ void DisplayServerOSX::global_menu_set_item_submenu(const String &p_menu_root, i } } -void DisplayServerOSX::global_menu_set_item_accelerator(const String &p_menu_root, int p_idx, Key p_keycode) { +void DisplayServerMacOS::global_menu_set_item_accelerator(const String &p_menu_root, int p_idx, Key p_keycode) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1321,14 +1318,14 @@ void DisplayServerOSX::global_menu_set_item_accelerator(const String &p_menu_roo } NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_keycode)]; - String keycode = KeyMappingOSX::keycode_get_native_string(p_keycode & KeyModifierMask::CODE_MASK); + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_keycode)]; + String keycode = KeyMappingMacOS::keycode_get_native_string(p_keycode & KeyModifierMask::CODE_MASK); [menu_item setKeyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; } } } -void DisplayServerOSX::global_menu_set_item_disabled(const String &p_menu_root, int p_idx, bool p_disabled) { +void DisplayServerMacOS::global_menu_set_item_disabled(const String &p_menu_root, int p_idx, bool p_disabled) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1343,7 +1340,7 @@ void DisplayServerOSX::global_menu_set_item_disabled(const String &p_menu_root, } } -void DisplayServerOSX::global_menu_set_item_tooltip(const String &p_menu_root, int p_idx, const String &p_tooltip) { +void DisplayServerMacOS::global_menu_set_item_tooltip(const String &p_menu_root, int p_idx, const String &p_tooltip) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1358,7 +1355,7 @@ void DisplayServerOSX::global_menu_set_item_tooltip(const String &p_menu_root, i } } -void DisplayServerOSX::global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) { +void DisplayServerMacOS::global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1376,7 +1373,7 @@ void DisplayServerOSX::global_menu_set_item_state(const String &p_menu_root, int } } -void DisplayServerOSX::global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) { +void DisplayServerMacOS::global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1394,7 +1391,7 @@ void DisplayServerOSX::global_menu_set_item_max_states(const String &p_menu_root } } -void DisplayServerOSX::global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) { +void DisplayServerMacOS::global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1421,7 +1418,7 @@ void DisplayServerOSX::global_menu_set_item_icon(const String &p_menu_root, int } } -int DisplayServerOSX::global_menu_get_item_count(const String &p_menu_root) const { +int DisplayServerMacOS::global_menu_get_item_count(const String &p_menu_root) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); @@ -1432,7 +1429,7 @@ int DisplayServerOSX::global_menu_get_item_count(const String &p_menu_root) cons } } -void DisplayServerOSX::global_menu_remove_item(const String &p_menu_root, int p_idx) { +void DisplayServerMacOS::global_menu_remove_item(const String &p_menu_root, int p_idx) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1444,7 +1441,7 @@ void DisplayServerOSX::global_menu_remove_item(const String &p_menu_root, int p_ } } -void DisplayServerOSX::global_menu_clear(const String &p_menu_root) { +void DisplayServerMacOS::global_menu_clear(const String &p_menu_root) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1458,42 +1455,42 @@ void DisplayServerOSX::global_menu_clear(const String &p_menu_root) { } } -bool DisplayServerOSX::tts_is_speaking() const { +bool DisplayServerMacOS::tts_is_speaking() const { ERR_FAIL_COND_V(!tts, false); return [tts isSpeaking]; } -bool DisplayServerOSX::tts_is_paused() const { +bool DisplayServerMacOS::tts_is_paused() const { ERR_FAIL_COND_V(!tts, false); return [tts isPaused]; } -Array DisplayServerOSX::tts_get_voices() const { +Array DisplayServerMacOS::tts_get_voices() const { ERR_FAIL_COND_V(!tts, Array()); return [tts getVoices]; } -void DisplayServerOSX::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { +void DisplayServerMacOS::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { ERR_FAIL_COND(!tts); [tts speak:p_text voice:p_voice volume:p_volume pitch:p_pitch rate:p_rate utterance_id:p_utterance_id interrupt:p_interrupt]; } -void DisplayServerOSX::tts_pause() { +void DisplayServerMacOS::tts_pause() { ERR_FAIL_COND(!tts); [tts pauseSpeaking]; } -void DisplayServerOSX::tts_resume() { +void DisplayServerMacOS::tts_resume() { ERR_FAIL_COND(!tts); [tts resumeSpeaking]; } -void DisplayServerOSX::tts_stop() { +void DisplayServerMacOS::tts_stop() { ERR_FAIL_COND(!tts); [tts stopSpeaking]; } -Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { +Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { _THREAD_SAFE_METHOD_ NSAlert *window = [[NSAlert alloc] init]; @@ -1531,7 +1528,7 @@ Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector return OK; } -Error DisplayServerOSX::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { +Error DisplayServerMacOS::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { _THREAD_SAFE_METHOD_ NSAlert *window = [[NSAlert alloc] init]; @@ -1563,7 +1560,7 @@ Error DisplayServerOSX::dialog_input_text(String p_title, String p_description, return OK; } -void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) { +void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) { _THREAD_SAFE_METHOD_ if (p_mode == mouse_mode) { @@ -1618,11 +1615,11 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) { } } -DisplayServer::MouseMode DisplayServerOSX::mouse_get_mode() const { +DisplayServer::MouseMode DisplayServerMacOS::mouse_get_mode() const { return mouse_mode; } -bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSPoint &r_mpos, NSTimeInterval p_timestamp) { +bool DisplayServerMacOS::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSPoint &r_mpos, NSTimeInterval p_timestamp) { _THREAD_SAFE_METHOD_ if (ignore_warp) { @@ -1644,7 +1641,7 @@ bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSP List<WarpEvent>::Element *F = warp_events.front(); while (F) { if (F->get().timestamp < p_timestamp) { - List<DisplayServerOSX::WarpEvent>::Element *E = F; + List<DisplayServerMacOS::WarpEvent>::Element *E = F; r_delta.x -= E->get().delta.x; r_delta.y -= E->get().delta.y; F = F->next(); @@ -1672,7 +1669,7 @@ bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSP // Save warp data. last_warp = [[NSProcessInfo processInfo] systemUptime]; - DisplayServerOSX::WarpEvent ev; + DisplayServerMacOS::WarpEvent ev; ev.timestamp = last_warp; ev.delta = r_delta; warp_events.push_back(ev); @@ -1681,7 +1678,7 @@ bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSP return false; } -void DisplayServerOSX::warp_mouse(const Point2i &p_position) { +void DisplayServerMacOS::warp_mouse(const Point2i &p_position) { _THREAD_SAFE_METHOD_ if (mouse_mode != MOUSE_MODE_CAPTURED) { @@ -1708,7 +1705,7 @@ void DisplayServerOSX::warp_mouse(const Point2i &p_position) { } } -Point2i DisplayServerOSX::mouse_get_position() const { +Point2i DisplayServerMacOS::mouse_get_position() const { _THREAD_SAFE_METHOD_ const NSPoint mouse_pos = [NSEvent mouseLocation]; @@ -1727,15 +1724,15 @@ Point2i DisplayServerOSX::mouse_get_position() const { return Vector2i(); } -void DisplayServerOSX::mouse_set_button_state(MouseButton p_state) { +void DisplayServerMacOS::mouse_set_button_state(MouseButton p_state) { last_button_state = p_state; } -MouseButton DisplayServerOSX::mouse_get_button_state() const { +MouseButton DisplayServerMacOS::mouse_get_button_state() const { return last_button_state; } -void DisplayServerOSX::clipboard_set(const String &p_text) { +void DisplayServerMacOS::clipboard_set(const String &p_text) { _THREAD_SAFE_METHOD_ NSString *copiedString = [NSString stringWithUTF8String:p_text.utf8().get_data()]; @@ -1746,7 +1743,7 @@ void DisplayServerOSX::clipboard_set(const String &p_text) { [pasteboard writeObjects:copiedStringArray]; } -String DisplayServerOSX::clipboard_get() const { +String DisplayServerMacOS::clipboard_get() const { _THREAD_SAFE_METHOD_ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; @@ -1767,14 +1764,14 @@ String DisplayServerOSX::clipboard_get() const { return ret; } -int DisplayServerOSX::get_screen_count() const { +int DisplayServerMacOS::get_screen_count() const { _THREAD_SAFE_METHOD_ NSArray *screenArray = [NSScreen screens]; return [screenArray count]; } -Point2i DisplayServerOSX::screen_get_position(int p_screen) const { +Point2i DisplayServerMacOS::screen_get_position(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1788,7 +1785,7 @@ Point2i DisplayServerOSX::screen_get_position(int p_screen) const { return position; } -Size2i DisplayServerOSX::screen_get_size(int p_screen) const { +Size2i DisplayServerMacOS::screen_get_size(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1805,7 +1802,7 @@ Size2i DisplayServerOSX::screen_get_size(int p_screen) const { return Size2i(); } -int DisplayServerOSX::screen_get_dpi(int p_screen) const { +int DisplayServerMacOS::screen_get_dpi(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1829,7 +1826,7 @@ int DisplayServerOSX::screen_get_dpi(int p_screen) const { return 72; } -float DisplayServerOSX::screen_get_scale(int p_screen) const { +float DisplayServerMacOS::screen_get_scale(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1847,14 +1844,14 @@ float DisplayServerOSX::screen_get_scale(int p_screen) const { return 1.f; } -float DisplayServerOSX::screen_get_max_scale() const { +float DisplayServerMacOS::screen_get_max_scale() const { _THREAD_SAFE_METHOD_ // Note: Do not update max display scale on screen configuration change, existing editor windows can't be rescaled on the fly. return display_max_scale; } -Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const { +Rect2i DisplayServerMacOS::screen_get_usable_rect(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1876,7 +1873,7 @@ Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const { return Rect2i(); } -float DisplayServerOSX::screen_get_refresh_rate(int p_screen) const { +float DisplayServerMacOS::screen_get_refresh_rate(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1894,7 +1891,7 @@ float DisplayServerOSX::screen_get_refresh_rate(int p_screen) const { return SCREEN_REFRESH_RATE_FALLBACK; } -Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const { +Vector<DisplayServer::WindowID> DisplayServerMacOS::get_window_list() const { _THREAD_SAFE_METHOD_ Vector<int> ret; @@ -1904,7 +1901,7 @@ Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const { return ret; } -DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ WindowID id = _create_window(p_mode, p_vsync_mode, p_rect); @@ -1917,7 +1914,7 @@ DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, V return id; } -void DisplayServerOSX::show_window(WindowID p_id) { +void DisplayServerMacOS::show_window(WindowID p_id) { WindowData &wd = windows[p_id]; popup_open(p_id); @@ -1928,7 +1925,7 @@ void DisplayServerOSX::show_window(WindowID p_id) { } } -void DisplayServerOSX::delete_sub_window(WindowID p_id) { +void DisplayServerMacOS::delete_sub_window(WindowID p_id) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_id)); @@ -1940,7 +1937,7 @@ void DisplayServerOSX::delete_sub_window(WindowID p_id) { [wd.window_object close]; } -void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1948,7 +1945,7 @@ void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callab wd.rect_changed_callback = p_callable; } -void DisplayServerOSX::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1956,7 +1953,7 @@ void DisplayServerOSX::window_set_window_event_callback(const Callable &p_callab wd.event_callback = p_callable; } -void DisplayServerOSX::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1964,21 +1961,21 @@ void DisplayServerOSX::window_set_input_event_callback(const Callable &p_callabl wd.input_event_callback = p_callable; } -void DisplayServerOSX::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; wd.input_text_callback = p_callable; } -void DisplayServerOSX::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; wd.drop_files_callback = p_callable; } -void DisplayServerOSX::window_set_title(const String &p_title, WindowID p_window) { +void DisplayServerMacOS::window_set_title(const String &p_title, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1987,7 +1984,7 @@ void DisplayServerOSX::window_set_title(const String &p_title, WindowID p_window [wd.window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]]; } -void DisplayServerOSX::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { +void DisplayServerMacOS::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1996,7 +1993,7 @@ void DisplayServerOSX::window_set_mouse_passthrough(const Vector<Vector2> &p_reg wd.mpath = p_region; } -int DisplayServerOSX::window_get_current_screen(WindowID p_window) const { +int DisplayServerMacOS::window_get_current_screen(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), -1); const WindowData &wd = windows[p_window]; @@ -2005,12 +2002,16 @@ int DisplayServerOSX::window_get_current_screen(WindowID p_window) const { return (index == NSNotFound) ? 0 : index; } -void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window) { +void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if (window_get_current_screen(p_window) == p_screen) { + return; + } + bool was_fullscreen = false; if (wd.fullscreen) { // Temporary exit fullscreen mode to move window. @@ -2027,7 +2028,7 @@ void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window } } -void DisplayServerOSX::window_set_exclusive(WindowID p_window, bool p_exclusive) { +void DisplayServerMacOS::window_set_exclusive(WindowID p_window, bool p_exclusive) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; @@ -2045,7 +2046,7 @@ void DisplayServerOSX::window_set_exclusive(WindowID p_window, bool p_exclusive) } } -Point2i DisplayServerOSX::window_get_position(WindowID p_window) const { +Point2i DisplayServerMacOS::window_get_position(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Point2i()); @@ -2068,7 +2069,7 @@ Point2i DisplayServerOSX::window_get_position(WindowID p_window) const { return pos; } -void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p_window) { +void DisplayServerMacOS::window_set_position(const Point2i &p_position, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2096,7 +2097,7 @@ void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); } -void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent) { +void DisplayServerMacOS::window_set_transient(WindowID p_window, WindowID p_parent) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(p_window == p_parent); @@ -2135,7 +2136,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent } } -void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOS::window_set_max_size(const Size2i p_size, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2155,7 +2156,7 @@ void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_windo } } -Size2i DisplayServerOSX::window_get_max_size(WindowID p_window) const { +Size2i DisplayServerMacOS::window_get_max_size(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); @@ -2163,7 +2164,7 @@ Size2i DisplayServerOSX::window_get_max_size(WindowID p_window) const { return wd.max_size; } -void DisplayServerOSX::window_set_min_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOS::window_set_min_size(const Size2i p_size, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2183,7 +2184,7 @@ void DisplayServerOSX::window_set_min_size(const Size2i p_size, WindowID p_windo } } -Size2i DisplayServerOSX::window_get_min_size(WindowID p_window) const { +Size2i DisplayServerMacOS::window_get_min_size(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); @@ -2192,7 +2193,7 @@ Size2i DisplayServerOSX::window_get_min_size(WindowID p_window) const { return wd.min_size; } -void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOS::window_set_size(const Size2i p_size, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2216,7 +2217,7 @@ void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) { _update_window_style(wd); } -Size2i DisplayServerOSX::window_get_size(WindowID p_window) const { +Size2i DisplayServerMacOS::window_get_size(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); @@ -2224,7 +2225,7 @@ Size2i DisplayServerOSX::window_get_size(WindowID p_window) const { return wd.size; } -Size2i DisplayServerOSX::window_get_real_size(WindowID p_window) const { +Size2i DisplayServerMacOS::window_get_real_size(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); @@ -2233,7 +2234,7 @@ Size2i DisplayServerOSX::window_get_real_size(WindowID p_window) const { return Size2i(frame.size.width, frame.size.height) * screen_get_max_scale(); } -void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { +void DisplayServerMacOS::window_set_mode(WindowMode p_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2302,7 +2303,7 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { } } -DisplayServer::WindowMode DisplayServerOSX::window_get_mode(WindowID p_window) const { +DisplayServer::WindowMode DisplayServerMacOS::window_get_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED); @@ -2324,11 +2325,11 @@ DisplayServer::WindowMode DisplayServerOSX::window_get_mode(WindowID p_window) c return WINDOW_MODE_WINDOWED; } -bool DisplayServerOSX::window_is_maximize_allowed(WindowID p_window) const { +bool DisplayServerMacOS::window_is_maximize_allowed(WindowID p_window) const { return true; } -void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { +void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2403,7 +2404,7 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } } -bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) const { +bool DisplayServerMacOS::window_get_flag(WindowFlags p_flag, WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), false); @@ -2439,12 +2440,12 @@ bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) co return false; } -void DisplayServerOSX::window_request_attention(WindowID p_window) { +void DisplayServerMacOS::window_request_attention(WindowID p_window) { // It's app global, ignore window id. [NSApp requestUserAttention:NSCriticalRequest]; } -void DisplayServerOSX::window_move_to_foreground(WindowID p_window) { +void DisplayServerMacOS::window_move_to_foreground(WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2458,11 +2459,11 @@ void DisplayServerOSX::window_move_to_foreground(WindowID p_window) { } } -bool DisplayServerOSX::window_can_draw(WindowID p_window) const { +bool DisplayServerMacOS::window_can_draw(WindowID p_window) const { return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED; } -bool DisplayServerOSX::can_any_window_draw() const { +bool DisplayServerMacOS::can_any_window_draw() const { _THREAD_SAFE_METHOD_ for (const KeyValue<WindowID, WindowData> &E : windows) { @@ -2473,7 +2474,7 @@ bool DisplayServerOSX::can_any_window_draw() const { return false; } -void DisplayServerOSX::window_set_ime_active(const bool p_active, WindowID p_window) { +void DisplayServerMacOS::window_set_ime_active(const bool p_active, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2486,7 +2487,7 @@ void DisplayServerOSX::window_set_ime_active(const bool p_active, WindowID p_win } } -void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_window) { +void DisplayServerMacOS::window_set_ime_position(const Point2i &p_pos, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2495,7 +2496,7 @@ void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_ wd.im_position = p_pos; } -DisplayServer::WindowID DisplayServerOSX::get_window_at_screen_position(const Point2i &p_position) const { +DisplayServer::WindowID DisplayServerMacOS::get_window_at_screen_position(const Point2i &p_position) const { Point2i position = p_position; position.y *= -1; position += _get_screens_origin(); @@ -2510,7 +2511,7 @@ DisplayServer::WindowID DisplayServerOSX::get_window_at_screen_position(const Po return INVALID_WINDOW_ID; } -int64_t DisplayServerOSX::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { +int64_t DisplayServerMacOS::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { ERR_FAIL_COND_V(!windows.has(p_window), 0); switch (p_handle_type) { case DISPLAY_HANDLE: { @@ -2528,27 +2529,27 @@ int64_t DisplayServerOSX::window_get_native_handle(HandleType p_handle_type, Win } } -void DisplayServerOSX::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { +void DisplayServerMacOS::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); windows[p_window].instance_id = p_instance; } -ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) const { +ObjectID DisplayServerMacOS::window_get_attached_instance_id(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), ObjectID()); return windows[p_window].instance_id; } -void DisplayServerOSX::gl_window_make_current(DisplayServer::WindowID p_window_id) { +void DisplayServerMacOS::gl_window_make_current(DisplayServer::WindowID p_window_id) { #if defined(GLES3_ENABLED) gl_manager->window_make_current(p_window_id); #endif } -void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { +void DisplayServerMacOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ #if defined(GLES3_ENABLED) if (gl_manager) { @@ -2562,7 +2563,7 @@ void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo #endif } -DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_window) const { +DisplayServer::VSyncMode DisplayServerMacOS::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ #if defined(GLES3_ENABLED) if (gl_manager) { @@ -2577,15 +2578,15 @@ DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_wind return DisplayServer::VSYNC_ENABLED; } -Point2i DisplayServerOSX::ime_get_selection() const { +Point2i DisplayServerMacOS::ime_get_selection() const { return im_selection; } -String DisplayServerOSX::ime_get_text() const { +String DisplayServerMacOS::ime_get_text() const { return im_text; } -void DisplayServerOSX::cursor_update_shape() { +void DisplayServerMacOS::cursor_update_shape() { _THREAD_SAFE_METHOD_ if (cursors[cursor_shape] != nullptr) { @@ -2649,7 +2650,7 @@ void DisplayServerOSX::cursor_update_shape() { } } -void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { +void DisplayServerMacOS::cursor_set_shape(CursorShape p_shape) { _THREAD_SAFE_METHOD_ ERR_FAIL_INDEX(p_shape, CURSOR_MAX); @@ -2667,11 +2668,11 @@ void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { cursor_update_shape(); } -DisplayServerOSX::CursorShape DisplayServerOSX::cursor_get_shape() const { +DisplayServerMacOS::CursorShape DisplayServerMacOS::cursor_get_shape() const { return cursor_shape; } -void DisplayServerOSX::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerMacOS::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { _THREAD_SAFE_METHOD_ if (p_cursor.is_valid()) { @@ -2783,20 +2784,20 @@ void DisplayServerOSX::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu } } -bool DisplayServerOSX::get_swap_cancel_ok() { +bool DisplayServerMacOS::get_swap_cancel_ok() { return false; } -int DisplayServerOSX::keyboard_get_layout_count() const { +int DisplayServerMacOS::keyboard_get_layout_count() const { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } return kbd_layouts.size(); } -void DisplayServerOSX::keyboard_set_current_layout(int p_index) { +void DisplayServerMacOS::keyboard_set_current_layout(int p_index) { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } ERR_FAIL_INDEX(p_index, kbd_layouts.size()); @@ -2824,44 +2825,44 @@ void DisplayServerOSX::keyboard_set_current_layout(int p_index) { } } -int DisplayServerOSX::keyboard_get_current_layout() const { +int DisplayServerMacOS::keyboard_get_current_layout() const { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } return current_layout; } -String DisplayServerOSX::keyboard_get_layout_language(int p_index) const { +String DisplayServerMacOS::keyboard_get_layout_language(int p_index) const { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } ERR_FAIL_INDEX_V(p_index, kbd_layouts.size(), ""); return kbd_layouts[p_index].code; } -String DisplayServerOSX::keyboard_get_layout_name(int p_index) const { +String DisplayServerMacOS::keyboard_get_layout_name(int p_index) const { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } ERR_FAIL_INDEX_V(p_index, kbd_layouts.size(), ""); return kbd_layouts[p_index].name; } -Key DisplayServerOSX::keyboard_get_keycode_from_physical(Key p_keycode) const { +Key DisplayServerMacOS::keyboard_get_keycode_from_physical(Key p_keycode) const { if (p_keycode == Key::PAUSE) { return p_keycode; } Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK; Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK; - unsigned int osx_keycode = KeyMappingOSX::unmap_key((Key)keycode_no_mod); - return (Key)(KeyMappingOSX::remap_key(osx_keycode, 0) | modifiers); + unsigned int macos_keycode = KeyMappingMacOS::unmap_key((Key)keycode_no_mod); + return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0) | modifiers); } -void DisplayServerOSX::process_events() { +void DisplayServerMacOS::process_events() { _THREAD_SAFE_METHOD_ while (true) { @@ -2904,7 +2905,7 @@ void DisplayServerOSX::process_events() { } } -void DisplayServerOSX::force_process_and_drop_events() { +void DisplayServerMacOS::force_process_and_drop_events() { _THREAD_SAFE_METHOD_ drop_events = true; @@ -2912,19 +2913,21 @@ void DisplayServerOSX::force_process_and_drop_events() { drop_events = false; } -void DisplayServerOSX::release_rendering_thread() { +void DisplayServerMacOS::release_rendering_thread() { } -void DisplayServerOSX::make_rendering_thread() { +void DisplayServerMacOS::make_rendering_thread() { } -void DisplayServerOSX::swap_buffers() { +void DisplayServerMacOS::swap_buffers() { #if defined(GLES3_ENABLED) - gl_manager->swap_buffers(); + if (gl_manager) { + gl_manager->swap_buffers(); + } #endif } -void DisplayServerOSX::set_native_icon(const String &p_filename) { +void DisplayServerMacOS::set_native_icon(const String &p_filename) { _THREAD_SAFE_METHOD_ Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::READ); @@ -2944,7 +2947,7 @@ void DisplayServerOSX::set_native_icon(const String &p_filename) { [NSApp setApplicationIconImage:icon]; } -void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { +void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) { _THREAD_SAFE_METHOD_ Ref<Image> img = p_icon; @@ -2983,15 +2986,15 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { [NSApp setApplicationIconImage:nsimg]; } -DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.", "Unable to initialize Video driver"); } return ds; } -Vector<String> DisplayServerOSX::get_rendering_drivers_func() { +Vector<String> DisplayServerMacOS::get_rendering_drivers_func() { Vector<String> drivers; #if defined(VULKAN_ENABLED) @@ -3004,11 +3007,11 @@ Vector<String> DisplayServerOSX::get_rendering_drivers_func() { return drivers; } -void DisplayServerOSX::register_osx_driver() { - register_create_function("osx", create_func, get_rendering_drivers_func); +void DisplayServerMacOS::register_macos_driver() { + register_create_function("macos", create_func, get_rendering_drivers_func); } -DisplayServer::WindowID DisplayServerOSX::window_get_active_popup() const { +DisplayServer::WindowID DisplayServerMacOS::window_get_active_popup() const { const List<WindowID>::Element *E = popup_list.back(); if (E) { return E->get(); @@ -3017,7 +3020,7 @@ DisplayServer::WindowID DisplayServerOSX::window_get_active_popup() const { } } -void DisplayServerOSX::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) { +void DisplayServerMacOS::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -3025,7 +3028,7 @@ void DisplayServerOSX::window_set_popup_safe_rect(WindowID p_window, const Rect2 wd.parent_safe_rect = p_rect; } -Rect2i DisplayServerOSX::window_get_popup_safe_rect(WindowID p_window) const { +Rect2i DisplayServerMacOS::window_get_popup_safe_rect(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Rect2i()); @@ -3033,7 +3036,7 @@ Rect2i DisplayServerOSX::window_get_popup_safe_rect(WindowID p_window) const { return wd.parent_safe_rect; } -void DisplayServerOSX::popup_open(WindowID p_window) { +void DisplayServerMacOS::popup_open(WindowID p_window) { _THREAD_SAFE_METHOD_ WindowData &wd = windows[p_window]; @@ -3051,7 +3054,7 @@ void DisplayServerOSX::popup_open(WindowID p_window) { } } if (C) { - send_window_event(windows[C->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + send_window_event(windows[C->get()], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); } if (was_empty && popup_list.is_empty()) { @@ -3063,7 +3066,7 @@ void DisplayServerOSX::popup_open(WindowID p_window) { } } -void DisplayServerOSX::popup_close(WindowID p_window) { +void DisplayServerMacOS::popup_close(WindowID p_window) { _THREAD_SAFE_METHOD_ bool was_empty = popup_list.is_empty(); @@ -3073,7 +3076,7 @@ void DisplayServerOSX::popup_close(WindowID p_window) { WindowID win_id = E->get(); popup_list.erase(E); - send_window_event(windows[win_id], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + send_window_event(windows[win_id], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); E = F; } if (!was_empty && popup_list.is_empty()) { @@ -3082,7 +3085,7 @@ void DisplayServerOSX::popup_close(WindowID p_window) { } } -bool DisplayServerOSX::mouse_process_popups(bool p_close) { +bool DisplayServerMacOS::mouse_process_popups(bool p_close) { _THREAD_SAFE_METHOD_ bool was_empty = popup_list.is_empty(); @@ -3091,7 +3094,7 @@ bool DisplayServerOSX::mouse_process_popups(bool p_close) { // Close all popups. List<WindowID>::Element *E = popup_list.front(); if (E) { - send_window_event(windows[E->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + send_window_event(windows[E->get()], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); closed = true; } if (!was_empty) { @@ -3123,7 +3126,7 @@ bool DisplayServerOSX::mouse_process_popups(bool p_close) { } } if (C) { - send_window_event(windows[C->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + send_window_event(windows[C->get()], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); closed = true; } if (!was_empty && popup_list.is_empty()) { @@ -3134,7 +3137,7 @@ bool DisplayServerOSX::mouse_process_popups(bool p_close) { return closed; } -DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); r_error = OK; @@ -3161,7 +3164,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode CGDisplayRegisterReconfigurationCallback(_displays_arrangement_changed, nullptr); // Init TTS - tts = [[TTS_OSX alloc] init]; + tts = [[TTS_MacOS alloc] init]; NSMenuItem *menu_item; NSString *title; @@ -3215,8 +3218,8 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3") { - GLManager_OSX::ContextType opengl_api_type = GLManager_OSX::GLES_3_0_COMPATIBLE; - gl_manager = memnew(GLManager_OSX(opengl_api_type)); + GLManager_MacOS::ContextType opengl_api_type = GLManager_MacOS::GLES_3_0_COMPATIBLE; + gl_manager = memnew(GLManager_MacOS(opengl_api_type)); if (gl_manager->initialize() != OK) { memdelete(gl_manager); gl_manager = nullptr; @@ -3228,7 +3231,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode #endif #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { - context_vulkan = memnew(VulkanContextOSX); + context_vulkan = memnew(VulkanContextMacOS); if (context_vulkan->initialize() != OK) { memdelete(context_vulkan); context_vulkan = nullptr; @@ -3265,7 +3268,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode #endif } -DisplayServerOSX::~DisplayServerOSX() { +DisplayServerMacOS::~DisplayServerMacOS() { // Destroy all windows. for (HashMap<WindowID, WindowData>::Iterator E = windows.begin(); E;) { HashMap<WindowID, WindowData>::Iterator F = E; diff --git a/platform/osx/export/codesign.cpp b/platform/macos/export/codesign.cpp index fd044c00cc..fd044c00cc 100644 --- a/platform/osx/export/codesign.cpp +++ b/platform/macos/export/codesign.cpp diff --git a/platform/osx/export/codesign.h b/platform/macos/export/codesign.h index 3a08c0ea86..fea7b117d0 100644 --- a/platform/osx/export/codesign.h +++ b/platform/macos/export/codesign.h @@ -38,8 +38,8 @@ // - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported). // - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only. -#ifndef CODESIGN_H -#define CODESIGN_H +#ifndef MACOS_CODESIGN_H +#define MACOS_CODESIGN_H #include "core/crypto/crypto_core.h" #include "core/io/dir_access.h" @@ -365,4 +365,4 @@ public: #endif // MODULE_REGEX_ENABLED -#endif // CODESIGN_H +#endif // MACOS_CODESIGN_H diff --git a/platform/osx/export/export.cpp b/platform/macos/export/export.cpp index bd35b39e9e..ff7457081f 100644 --- a/platform/osx/export/export.cpp +++ b/platform/macos/export/export.cpp @@ -32,11 +32,11 @@ #include "export_plugin.h" -void register_osx_exporter() { +void register_macos_exporter() { EDITOR_DEF("export/macos/force_builtin_codesign", false); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::BOOL, "export/macos/force_builtin_codesign", PROPERTY_HINT_NONE)); - Ref<EditorExportPlatformOSX> platform; + Ref<EditorExportPlatformMacOS> platform; platform.instantiate(); EditorExport::get_singleton()->add_export_platform(platform); diff --git a/platform/iphone/export/export.h b/platform/macos/export/export.h index adb3c23957..260c691209 100644 --- a/platform/iphone/export/export.h +++ b/platform/macos/export/export.h @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IPHONE_EXPORT_H -#define IPHONE_EXPORT_H +#ifndef MACOS_EXPORT_H +#define MACOS_EXPORT_H -void register_iphone_exporter(); +void register_macos_exporter(); -#endif // IPHONE_EXPORT_H +#endif // MACOS_EXPORT_H diff --git a/platform/osx/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 7010709123..fd0781ac50 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -37,7 +37,7 @@ #include "modules/modules_enabled.gen.h" // For regex. -void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { +void EditorExportPlatformMacOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { if (p_preset->get("texture_format/s3tc")) { r_features->push_back("s3tc"); } @@ -51,7 +51,7 @@ void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> r_features->push_back("64"); } -bool EditorExportPlatformOSX::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const { +bool EditorExportPlatformMacOS::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const { // These options are not supported by built-in codesign, used on non macOS host. if (!OS::get_singleton()->has_feature("macos")) { if (p_option == "codesign/identity" || p_option == "codesign/timestamp" || p_option == "codesign/hardened_runtime" || p_option == "codesign/custom_options" || p_option.begins_with("notarization/")) { @@ -68,7 +68,7 @@ bool EditorExportPlatformOSX::get_export_option_visibility(const String &p_optio return true; } -void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) { +void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options) { r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); @@ -214,7 +214,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, memcpy(&p_dest.write[ofs], result.ptr(), res_size); } -void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { +void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { Ref<ImageTexture> it = memnew(ImageTexture); Vector<uint8_t> data; @@ -252,7 +252,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ if (icon_infos[i].is_png) { // Encode PNG icon. - it->create_from_image(copy); + it->set_image(copy); String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png"); ResourceSaver::save(path, it); @@ -320,7 +320,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ p_data = data; } -void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) { +void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) { String str; String strnew; str.parse_utf8((const char *)plist.ptr(), plist.size()); @@ -407,14 +407,14 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset } /** - * If we're running the OSX version of the Godot editor we'll: + * If we're running the macOS version of the Godot editor we'll: * - export our application bundle to a temporary folder * - attempt to code sign it * - and then wrap it up in a DMG */ -Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) { -#ifdef OSX_ENABLED +Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) { +#ifdef MACOS_ENABLED List<String> args; args.push_back("altool"); @@ -468,7 +468,7 @@ Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset return OK; } -Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) { +Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) { bool force_builtin_codesign = EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign"); bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-"); @@ -476,7 +476,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese print_verbose("using built-in codesign..."); #ifdef MODULE_REGEX_ENABLED -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED if (p_preset->get("codesign/timestamp") && p_warn) { add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!")); } @@ -566,9 +566,9 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese } } -Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, +Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code) { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED static Vector<String> extensions_to_sign; if (extensions_to_sign.is_empty()) { @@ -615,7 +615,7 @@ Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset return OK; } -Error EditorExportPlatformOSX::_copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, +Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, const String &p_in_app_path, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, bool p_should_error_on_non_code_sign) { @@ -644,14 +644,14 @@ Error EditorExportPlatformOSX::_copy_and_sign_files(Ref<DirAccess> &dir_access, return err; } -Error EditorExportPlatformOSX::_export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, +Error EditorExportPlatformMacOS::_export_macos_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name, Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path) { Error error{ OK }; - const Vector<String> &osx_plugins{ p_editor_export_plugin->get_osx_plugin_files() }; - for (int i = 0; i < osx_plugins.size(); ++i) { - String src_path{ ProjectSettings::get_singleton()->globalize_path(osx_plugins[i]) }; + const Vector<String> &macos_plugins{ p_editor_export_plugin->get_macos_plugin_files() }; + for (int i = 0; i < macos_plugins.size(); ++i) { + String src_path{ ProjectSettings::get_singleton()->globalize_path(macos_plugins[i]) }; String path_in_app{ p_app_path_name + "/Contents/PlugIns/" + src_path.get_file() }; error = _copy_and_sign_files(dir_access, src_path, path_in_app, p_sign_enabled, p_preset, p_ent_path, false); if (error != OK) { @@ -661,7 +661,7 @@ Error EditorExportPlatformOSX::_export_osx_plugins_for(Ref<EditorExportPlugin> p return error; } -Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { +Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { List<String> args; if (FileAccess::exists(p_dmg_path)) { @@ -697,7 +697,7 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin return OK; } -Error EditorExportPlatformOSX::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { +Error EditorExportPlatformMacOS::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); if (f.is_null()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path)); @@ -706,19 +706,30 @@ Error EditorExportPlatformOSX::_export_debug_script(const Ref<EditorExportPreset f->store_line("#!/bin/sh"); f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'"); - f->store_line("function realpath() { python -c \"import os,sys; print(os.path.realpath(sys.argv[1]))\" \"$0\"; }"); - f->store_line("base_path=\"$(dirname \"$(realpath \"$0\")\")\""); - f->store_line("\"$base_path/" + p_pkg_name + "\" \"$@\""); + f->store_line(""); + f->store_line("function app_realpath() {"); + f->store_line(" SOURCE=$1"); + f->store_line(" while [ -h \"$SOURCE\" ]; do"); + f->store_line(" DIR=$(dirname \"$SOURCE\")"); + f->store_line(" SOURCE=$(readlink \"$SOURCE\")"); + f->store_line(" [[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE"); + f->store_line(" done"); + f->store_line(" echo \"$( cd -P \"$( dirname \"$SOURCE\" )\" >/dev/null 2>&1 && pwd )\""); + f->store_line("}"); + f->store_line(""); + f->store_line("BASE_PATH=\"$(app_realpath \"${BASH_SOURCE[0]}\")\""); + f->store_line("\"$BASE_PATH/" + p_pkg_name + "\" \"$@\""); + f->store_line(""); return OK; } -Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { +Error EditorExportPlatformMacOS::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; - EditorProgress ep("export", "Exporting for OSX", 3, true); + EditorProgress ep("export", "Exporting for macOS", 3, true); if (p_debug) { src_pkg_name = p_preset->get("custom_template/debug"); @@ -728,7 +739,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (src_pkg_name.is_empty()) { String err; - src_pkg_name = find_export_template("osx.zip", &err); + src_pkg_name = find_export_template("macos.zip", &err); if (src_pkg_name.is_empty()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found.")); return ERR_FILE_NOT_FOUND; @@ -755,7 +766,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p int ret = unzGoToFirstFile(src_pkg_zip); - String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".64"; + String binary_to_use = "godot_macos_" + String(p_debug ? "debug" : "release") + ".universal"; String pkg_name; if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { @@ -984,7 +995,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p unzCloseCurrentFile(src_pkg_zip); // Write. - file = file.replace_first("osx_template.app/", ""); + file = file.replace_first("macos_template.app/", ""); if (((info.external_fa >> 16L) & 0120000) == 0120000) { #ifndef UNIX_ENABLED @@ -1053,19 +1064,19 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } if (data.size() > 0) { - if (file.find("/data.mono.osx.64.release_debug/") != -1) { + if (file.find("/data.mono.macos.release_debug.universal/") != -1) { if (!p_debug) { ret = unzGoToNextFile(src_pkg_zip); continue; // skip } - file = file.replace("/data.mono.osx.64.release_debug/", "/GodotSharp/"); + file = file.replace("/data.mono.macos.release_debug.universal/", "/GodotSharp/"); } - if (file.find("/data.mono.osx.64.release/") != -1) { + if (file.find("/data.mono.macos.release.universal/") != -1) { if (p_debug) { ret = unzGoToNextFile(src_pkg_zip); continue; // skip } - file = file.replace("/data.mono.osx.64.release/", "/GodotSharp/"); + file = file.replace("/data.mono.macos.release.universal/", "/GodotSharp/"); } if (file.ends_with(".dylib")) { @@ -1086,6 +1097,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE); if (f.is_valid()) { f->store_buffer(data.ptr(), data.size()); + f.unref(); if (is_execute) { // chmod with 0755 if the file is executable. FileAccess::set_unix_permissions(file, 0755); @@ -1298,7 +1310,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p bool ad_hoc = true; if (err == OK) { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED String sign_identity = p_preset->get("codesign/identity"); #else String sign_identity = "-"; @@ -1329,7 +1341,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Vector<Ref<EditorExportPlugin>> export_plugins{ EditorExport::get_singleton()->get_export_plugins() }; for (int i = 0; i < export_plugins.size(); ++i) { - err = _export_osx_plugins_for(export_plugins[i], tmp_app_path_name, da, sign_enabled, p_preset, ent_path); + err = _export_macos_plugins_for(export_plugins[i], tmp_app_path_name, da, sign_enabled, p_preset, ent_path); if (err != OK) { break; } @@ -1386,7 +1398,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } } -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool noto_enabled = p_preset->get("notarization/enable"); if (err == OK && noto_enabled) { if (export_format == "app") { @@ -1419,7 +1431,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p return err; } -void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) { +void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) { String dir = p_folder.is_empty() ? p_root_path : p_root_path.plus_file(p_folder); Ref<DirAccess> da = DirAccess::open(dir); @@ -1536,7 +1548,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String da->list_dir_end(); } -bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { +bool EditorExportPlatformMacOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; @@ -1559,7 +1571,7 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset // Look for export templates (official templates, check only is custom templates are not set). if (!dvalid || !rvalid) { - dvalid = exists_export_template("osx.zip", &err); + dvalid = exists_export_template("macos.zip", &err); rvalid = dvalid; // Both in the same ZIP. } @@ -1575,7 +1587,7 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset bool sign_enabled = p_preset->get("codesign/enable"); -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool noto_enabled = p_preset->get("notarization/enable"); bool ad_hoc = ((p_preset->get("codesign/identity") == "") || (p_preset->get("codesign/identity") == "-")); @@ -1664,11 +1676,9 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset return valid; } -EditorExportPlatformOSX::EditorExportPlatformOSX() { - Ref<Image> img = memnew(Image(_osx_logo)); - logo.instantiate(); - logo->create_from_image(img); +EditorExportPlatformMacOS::EditorExportPlatformMacOS() { + logo = ImageTexture::create_from_image(memnew(Image(_macos_logo))); } -EditorExportPlatformOSX::~EditorExportPlatformOSX() { +EditorExportPlatformMacOS::~EditorExportPlatformMacOS() { } diff --git a/platform/osx/export/export_plugin.h b/platform/macos/export/export_plugin.h index ec97d4139f..4f4b17594c 100644 --- a/platform/osx/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OSX_EXPORT_PLUGIN_H -#define OSX_EXPORT_PLUGIN_H +#ifndef MACOS_EXPORT_PLUGIN_H +#define MACOS_EXPORT_PLUGIN_H #include "core/config/project_settings.h" #include "core/io/dir_access.h" @@ -39,14 +39,14 @@ #include "core/io/zip_io.h" #include "core/os/os.h" #include "core/version.h" -#include "editor/editor_export.h" #include "editor/editor_settings.h" -#include "platform/osx/logo.gen.h" +#include "editor/export/editor_export.h" +#include "platform/macos/logo.gen.h" #include <sys/stat.h> -class EditorExportPlatformOSX : public EditorExportPlatform { - GDCLASS(EditorExportPlatformOSX, EditorExportPlatform); +class EditorExportPlatformMacOS : public EditorExportPlatform { + GDCLASS(EditorExportPlatformMacOS, EditorExportPlatform); int version_code = 0; @@ -61,7 +61,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform { Error _copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, const String &p_in_app_path, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, bool p_should_error_on_non_code_sign); - Error _export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name, + Error _export_macos_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name, Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); @@ -69,7 +69,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform { Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); bool use_codesign() const { return true; } -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool use_dmg() const { return true; } #else bool use_dmg() const { return false; } @@ -130,8 +130,8 @@ public: virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override { } - EditorExportPlatformOSX(); - ~EditorExportPlatformOSX(); + EditorExportPlatformMacOS(); + ~EditorExportPlatformMacOS(); }; -#endif +#endif // MACOS_EXPORT_PLUGIN_H diff --git a/platform/osx/export/lipo.cpp b/platform/macos/export/lipo.cpp index 82baf18c52..82baf18c52 100644 --- a/platform/osx/export/lipo.cpp +++ b/platform/macos/export/lipo.cpp diff --git a/platform/osx/export/lipo.h b/platform/macos/export/lipo.h index 0e419be17e..516ef99860 100644 --- a/platform/osx/export/lipo.h +++ b/platform/macos/export/lipo.h @@ -30,8 +30,8 @@ // Universal / Universal 2 fat binary file creator and extractor. -#ifndef LIPO_H -#define LIPO_H +#ifndef MACOS_LIPO_H +#define MACOS_LIPO_H #include "core/io/file_access.h" #include "core/object/ref_counted.h" @@ -73,4 +73,4 @@ public: #endif // MODULE_REGEX_ENABLED -#endif // LIPO_H +#endif // MACOS_LIPO_H diff --git a/platform/osx/export/macho.cpp b/platform/macos/export/macho.cpp index e6e67eff06..e6e67eff06 100644 --- a/platform/osx/export/macho.cpp +++ b/platform/macos/export/macho.cpp diff --git a/platform/osx/export/macho.h b/platform/macos/export/macho.h index 6cfc3c44f5..7ef0d9067e 100644 --- a/platform/osx/export/macho.h +++ b/platform/macos/export/macho.h @@ -30,8 +30,8 @@ // Mach-O binary object file format parser and editor. -#ifndef MACHO_H -#define MACHO_H +#ifndef MACOS_MACHO_H +#define MACOS_MACHO_H #include "core/crypto/crypto.h" #include "core/crypto/crypto_core.h" @@ -212,4 +212,4 @@ public: #endif // MODULE_REGEX_ENABLED -#endif // MACHO_H +#endif // MACOS_MACHO_H diff --git a/platform/osx/export/plist.cpp b/platform/macos/export/plist.cpp index 36de9dd34b..36de9dd34b 100644 --- a/platform/osx/export/plist.cpp +++ b/platform/macos/export/plist.cpp diff --git a/platform/osx/export/plist.h b/platform/macos/export/plist.h index ba9eaec196..79cb928d0a 100644 --- a/platform/osx/export/plist.h +++ b/platform/macos/export/plist.h @@ -30,8 +30,8 @@ // Property list file format (application/x-plist) parser, property list ASN-1 serialization. -#ifndef PLIST_H -#define PLIST_H +#ifndef MACOS_PLIST_H +#define MACOS_PLIST_H #include "core/crypto/crypto_core.h" #include "core/io/file_access.h" @@ -113,4 +113,4 @@ public: #endif // MODULE_REGEX_ENABLED -#endif // PLIST_H +#endif // MACOS_PLIST_H diff --git a/platform/osx/gl_manager_osx_legacy.h b/platform/macos/gl_manager_macos_legacy.h index 2d4913a7a6..8752086551 100644 --- a/platform/osx/gl_manager_osx_legacy.h +++ b/platform/macos/gl_manager_macos_legacy.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gl_manager_osx_legacy.h */ +/* gl_manager_macos_legacy.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GL_MANAGER_OSX_LEGACY_H -#define GL_MANAGER_OSX_LEGACY_H +#ifndef GL_MANAGER_MACOS_LEGACY_H +#define GL_MANAGER_MACOS_LEGACY_H -#if defined(OSX_ENABLED) && defined(GLES3_ENABLED) +#if defined(MACOS_ENABLED) && defined(GLES3_ENABLED) #include "core/error/error_list.h" #include "core/os/os.h" @@ -42,7 +42,7 @@ #import <ApplicationServices/ApplicationServices.h> #import <CoreVideo/CoreVideo.h> -class GLManager_OSX { +class GLManager_MacOS { public: enum ContextType { GLES_3_0_COMPATIBLE, @@ -89,9 +89,10 @@ public: void set_use_vsync(bool p_use); bool is_using_vsync() const; - GLManager_OSX(ContextType p_context_type); - ~GLManager_OSX(); + GLManager_MacOS(ContextType p_context_type); + ~GLManager_MacOS(); }; -#endif // OSX_ENABLED && GLES3_ENABLED -#endif // GL_MANAGER_OSX_LEGACY_H +#endif // MACOS_ENABLED && GLES3_ENABLED + +#endif // GL_MANAGER_MACOS_LEGACY_H diff --git a/platform/osx/gl_manager_osx_legacy.mm b/platform/macos/gl_manager_macos_legacy.mm index c769d7f5c5..e6bb7aaa85 100644 --- a/platform/osx/gl_manager_osx_legacy.mm +++ b/platform/macos/gl_manager_macos_legacy.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gl_manager_osx_legacy.mm */ +/* gl_manager_macos_legacy.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gl_manager_osx_legacy.h" +#include "gl_manager_macos_legacy.h" -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED #ifdef GLES3_ENABLED #include <stdio.h> #include <stdlib.h> -Error GLManager_OSX::create_context(GLWindow &win) { +Error GLManager_MacOS::create_context(GLWindow &win) { NSOpenGLPixelFormatAttribute attributes[] = { NSOpenGLPFADoubleBuffer, NSOpenGLPFAClosestPolicy, @@ -62,7 +62,7 @@ Error GLManager_OSX::create_context(GLWindow &win) { return OK; } -Error GLManager_OSX::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) { +Error GLManager_MacOS::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) { GLWindow win; win.width = p_width; win.height = p_height; @@ -78,7 +78,7 @@ Error GLManager_OSX::window_create(DisplayServer::WindowID p_window_id, id p_vie return OK; } -void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { +void GLManager_MacOS::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { if (!windows.has(p_window_id)) { return; } @@ -102,7 +102,7 @@ void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_wid [win.context update]; } -int GLManager_OSX::window_get_width(DisplayServer::WindowID p_window_id) { +int GLManager_MacOS::window_get_width(DisplayServer::WindowID p_window_id) { if (!windows.has(p_window_id)) { return 0; } @@ -111,7 +111,7 @@ int GLManager_OSX::window_get_width(DisplayServer::WindowID p_window_id) { return win.width; } -int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) { +int GLManager_MacOS::window_get_height(DisplayServer::WindowID p_window_id) { if (!windows.has(p_window_id)) { return 0; } @@ -120,7 +120,7 @@ int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) { return win.height; } -void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) { +void GLManager_MacOS::window_destroy(DisplayServer::WindowID p_window_id) { if (!windows.has(p_window_id)) { return; } @@ -132,7 +132,7 @@ void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) { windows.erase(p_window_id); } -void GLManager_OSX::release_current() { +void GLManager_MacOS::release_current() { if (current_window == DisplayServer::INVALID_WINDOW_ID) { return; } @@ -140,7 +140,7 @@ void GLManager_OSX::release_current() { [NSOpenGLContext clearCurrentContext]; } -void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) { +void GLManager_MacOS::window_make_current(DisplayServer::WindowID p_window_id) { if (current_window == p_window_id) { return; } @@ -154,7 +154,7 @@ void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) { current_window = p_window_id; } -void GLManager_OSX::make_current() { +void GLManager_MacOS::make_current() { if (current_window == DisplayServer::INVALID_WINDOW_ID) { return; } @@ -166,13 +166,13 @@ void GLManager_OSX::make_current() { [win.context makeCurrentContext]; } -void GLManager_OSX::swap_buffers() { +void GLManager_MacOS::swap_buffers() { for (const KeyValue<DisplayServer::WindowID, GLWindow> &E : windows) { [E.value.context flushBuffer]; } } -void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) { +void GLManager_MacOS::window_update(DisplayServer::WindowID p_window_id) { if (!windows.has(p_window_id)) { return; } @@ -181,7 +181,7 @@ void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) { [win.context update]; } -void GLManager_OSX::window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled) { +void GLManager_MacOS::window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled) { if (!windows.has(p_window_id)) { return; } @@ -197,11 +197,11 @@ void GLManager_OSX::window_set_per_pixel_transparency_enabled(DisplayServer::Win [win.context update]; } -Error GLManager_OSX::initialize() { +Error GLManager_MacOS::initialize() { return OK; } -void GLManager_OSX::set_use_vsync(bool p_use) { +void GLManager_MacOS::set_use_vsync(bool p_use) { use_vsync = p_use; CGLContextObj ctx = CGLGetCurrentContext(); @@ -212,17 +212,17 @@ void GLManager_OSX::set_use_vsync(bool p_use) { } } -bool GLManager_OSX::is_using_vsync() const { +bool GLManager_MacOS::is_using_vsync() const { return use_vsync; } -GLManager_OSX::GLManager_OSX(ContextType p_context_type) { +GLManager_MacOS::GLManager_MacOS(ContextType p_context_type) { context_type = p_context_type; } -GLManager_OSX::~GLManager_OSX() { +GLManager_MacOS::~GLManager_MacOS() { release_current(); } #endif // GLES3_ENABLED -#endif // OSX +#endif // MACOS_ENABLED diff --git a/platform/osx/godot_application.h b/platform/macos/godot_application.h index 8d48a659f3..8d48a659f3 100644 --- a/platform/osx/godot_application.h +++ b/platform/macos/godot_application.h diff --git a/platform/osx/godot_application.mm b/platform/macos/godot_application.mm index 13313a025a..3f71c77fd1 100644 --- a/platform/osx/godot_application.mm +++ b/platform/macos/godot_application.mm @@ -30,12 +30,12 @@ #include "godot_application.h" -#include "display_server_osx.h" +#include "display_server_macos.h" @implementation GodotApplication - (void)sendEvent:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { if ([event type] == NSEventTypeLeftMouseDown || [event type] == NSEventTypeRightMouseDown || [event type] == NSEventTypeOtherMouseDown) { if (ds->mouse_process_popups()) { diff --git a/platform/osx/godot_application_delegate.h b/platform/macos/godot_application_delegate.h index 8eec762d8f..f5b67b580f 100644 --- a/platform/osx/godot_application_delegate.h +++ b/platform/macos/godot_application_delegate.h @@ -40,6 +40,7 @@ - (void)forceUnbundledWindowActivationHackStep1; - (void)forceUnbundledWindowActivationHackStep2; - (void)forceUnbundledWindowActivationHackStep3; +- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; @end #endif // GODOT_APPLICATION_DELEGATE_H diff --git a/platform/osx/godot_application_delegate.mm b/platform/macos/godot_application_delegate.mm index dc82075c44..bacdcc2bc4 100644 --- a/platform/osx/godot_application_delegate.mm +++ b/platform/macos/godot_application_delegate.mm @@ -30,8 +30,8 @@ #include "godot_application_delegate.h" -#include "display_server_osx.h" -#include "os_osx.h" +#include "display_server_macos.h" +#include "os_macos.h" @implementation GodotApplicationDelegate @@ -67,8 +67,54 @@ } } +- (id)init { + self = [super init]; + + NSAppleEventManager *aem = [NSAppleEventManager sharedAppleEventManager]; + [aem setEventHandler:self andSelector:@selector(handleAppleEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; + [aem setEventHandler:self andSelector:@selector(handleAppleEvent:withReplyEvent:) forEventClass:kCoreEventClass andEventID:kAEOpenDocuments]; + + return self; +} + +- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { + OS_MacOS *os = (OS_MacOS *)OS::get_singleton(); + if (!event || !os) { + return; + } + + List<String> args; + if (([event eventClass] == kInternetEventClass) && ([event eventID] == kAEGetURL)) { + // Opening URL scheme. + NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + args.push_back(vformat("--uri=\"%s\"", String::utf8([url UTF8String]))); + } + + if (([event eventClass] == kCoreEventClass) && ([event eventID] == kAEOpenDocuments)) { + // Opening file association. + NSAppleEventDescriptor *files = [event paramDescriptorForKeyword:keyDirectObject]; + if (files) { + NSInteger count = [files numberOfItems]; + for (NSInteger i = 1; i <= count; i++) { + NSURL *url = [NSURL URLWithString:[[files descriptorAtIndex:i] stringValue]]; + args.push_back(String::utf8([url.path UTF8String])); + } + } + } + + if (!args.is_empty()) { + if (os->get_main_loop()) { + // Application is already running, open a new instance with the URL/files as command line arguments. + os->create_instance(args); + } else { + // Application is just started, add to the list of command line arguments and continue. + os->set_cmdline_platform_args(args); + } + } +} + - (void)applicationDidResignActive:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->mouse_process_popups(true); } @@ -84,14 +130,14 @@ } - (void)globalMenuCallback:(id)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { return ds->menu_callback(sender); } } - (NSMenu *)applicationDockMenu:(NSApplication *)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { return ds->get_dock_menu(); } else { @@ -99,35 +145,16 @@ } } -- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename { - // Note: may be called called before main loop init! - OS_OSX *os = (OS_OSX *)OS::get_singleton(); - if (os) { - os->set_open_with_filename(String::utf8([filename UTF8String])); - } - -#ifdef TOOLS_ENABLED - // Open new instance. - if (os && os->get_main_loop()) { - List<String> args; - args.push_back(os->get_open_with_filename()); - String exec = os->get_executable_path(); - os->create_process(exec, args); - } -#endif - return YES; -} - - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { - ds->send_window_event(ds->get_window(DisplayServerOSX::MAIN_WINDOW_ID), DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + ds->send_window_event(ds->get_window(DisplayServerMacOS::MAIN_WINDOW_ID), DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); } return NSTerminateCancel; } - (void)showAbout:(id)sender { - OS_OSX *os = (OS_OSX *)OS::get_singleton(); + OS_MacOS *os = (OS_MacOS *)OS::get_singleton(); if (os && os->get_main_loop()) { os->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT); } diff --git a/platform/osx/godot_content_view.h b/platform/macos/godot_content_view.h index 7942d716dc..353305aec1 100644 --- a/platform/osx/godot_content_view.h +++ b/platform/macos/godot_content_view.h @@ -52,6 +52,7 @@ bool ime_input_event_in_progress; bool mouse_down_control; bool ignore_momentum_scroll; + bool last_pen_inverted; } - (void)processScrollEvent:(NSEvent *)event button:(MouseButton)button factor:(double)factor; diff --git a/platform/osx/godot_content_view.mm b/platform/macos/godot_content_view.mm index e96f0a8098..9ca7498a15 100644 --- a/platform/osx/godot_content_view.mm +++ b/platform/macos/godot_content_view.mm @@ -30,8 +30,8 @@ #include "godot_content_view.h" -#include "display_server_osx.h" -#include "key_mapping_osx.h" +#include "display_server_macos.h" +#include "key_mapping_macos.h" @implementation GodotContentView @@ -42,6 +42,7 @@ ime_input_event_in_progress = false; mouse_down_control = false; ignore_momentum_scroll = false; + last_pen_inverted = false; [self updateTrackingAreas]; if (@available(macOS 10.13, *)) { @@ -55,7 +56,7 @@ return self; } -- (void)setWindowID:(DisplayServerOSX::WindowID)wid { +- (void)setWindowID:(DisplayServerMacOS::WindowID)wid { window_id = wid; } @@ -66,7 +67,7 @@ } - (void)updateLayer { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); ds->window_update(window_id); [super updateLayer]; } @@ -105,12 +106,12 @@ return; } - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (wd.im_active) { ime_input_event_in_progress = true; ds->update_im_text(Point2i(selectedRange.location, selectedRange.length), String::utf8([[marked_text mutableString] UTF8String])); @@ -125,12 +126,12 @@ ime_input_event_in_progress = false; [[marked_text mutableString] setString:@""]; - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (wd.im_active) { ds->update_im_text(Point2i(), String()); } @@ -149,12 +150,12 @@ } - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return NSMakeRect(0, 0, 0, 0); } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); const NSRect content_rect = [wd.window_view frame]; const float scale = ds->screen_get_max_scale(); NSRect point_in_window_rect = NSMakeRect(wd.im_position.x / scale, content_rect.size.height - (wd.im_position.y / scale) - 1, 0, 0); @@ -190,7 +191,7 @@ return; } - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { [self cancelComposition]; return; @@ -209,10 +210,10 @@ continue; } - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = true; ke.echo = false; ke.raw = false; // IME input event. @@ -236,12 +237,12 @@ } - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return NO; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (!wd.drop_files_callback.is_null()) { Vector<String> files; NSPasteboard *pboard = [sender draggingPasteboard]; @@ -275,12 +276,12 @@ // MARK: Focus - (BOOL)canBecomeKeyView { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return YES; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); return !wd.no_focus && !wd.is_popup; } @@ -291,7 +292,7 @@ // MARK: Mouse - (void)cursorUpdate:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds) { return; } @@ -300,12 +301,12 @@ } - (void)processMouseEvent:(NSEvent *)event index:(MouseButton)index mask:(MouseButton)mask pressed:(bool)pressed { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); MouseButton last_button_state = ds->mouse_get_button_state(); if (pressed) { @@ -355,12 +356,12 @@ } - (void)mouseMoved:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); NSPoint delta = NSMakePoint([event deltaX], [event deltaY]); NSPoint mpos = [event locationInWindow]; @@ -377,9 +378,15 @@ ds->update_mouse_pos(wd, mpos); mm->set_position(wd.mouse_pos); mm->set_pressure([event pressure]); - if ([event subtype] == NSEventSubtypeTabletPoint) { + NSEventSubtype subtype = [event subtype]; + if (subtype == NSEventSubtypeTabletPoint) { const NSPoint p = [event tilt]; mm->set_tilt(Vector2(p.x, p.y)); + mm->set_pen_inverted(last_pen_inverted); + } else if (subtype == NSEventSubtypeTabletProximity) { + // Check if using the eraser end of pen only on proximity event. + last_pen_inverted = [event pointingDeviceType] == NSPointingDeviceTypeEraser; + mm->set_pen_inverted(last_pen_inverted); } mm->set_global_position(wd.mouse_pos); mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity()); @@ -431,38 +438,38 @@ } - (void)mouseExited:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_CAPTURED) { - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_EXIT); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_MOUSE_EXIT); } } - (void)mouseEntered:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_CAPTURED) { - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_ENTER); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_MOUSE_ENTER); } ds->cursor_update_shape(); } - (void)magnifyWithEvent:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); Ref<InputEventMagnifyGesture> ev; ev.instantiate(); @@ -490,12 +497,12 @@ // MARK: Keyboard - (void)keyDown:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ignore_momentum_scroll = true; @@ -504,7 +511,7 @@ NSString *characters = [event characters]; NSUInteger length = [characters length]; - if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]))) { + if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]))) { // Fallback unicode character handler used if IME is not active. Char16String text; text.resize([characters length] + 1); @@ -516,28 +523,28 @@ for (int i = 0; i < u32text.length(); i++) { const char32_t codepoint = u32text[i]; - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = true; ke.echo = [event isARepeat]; - ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]); - ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]); + ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]); + ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]); ke.raw = true; ke.unicode = codepoint; ds->push_to_key_event_buffer(ke); } } else { - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = true; ke.echo = [event isARepeat]; - ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]); - ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]); + ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]); + ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]); ke.raw = false; ke.unicode = 0; @@ -552,7 +559,7 @@ } - (void)flagsChanged:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } @@ -560,7 +567,7 @@ // Ignore all input if IME input is in progress if (!ime_input_event_in_progress) { - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; ke.echo = false; @@ -601,9 +608,9 @@ return; } - ke.osx_state = mod; - ke.keycode = KeyMappingOSX::remap_key(key, mod); - ke.physical_keycode = KeyMappingOSX::translate_key(key); + ke.macos_state = mod; + ke.keycode = KeyMappingMacOS::remap_key(key, mod); + ke.physical_keycode = KeyMappingMacOS::translate_key(key); ke.unicode = 0; ds->push_to_key_event_buffer(ke); @@ -611,12 +618,12 @@ } - (void)keyUp:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); // Ignore all input if IME input is in progress. if (!ime_input_event_in_progress) { @@ -624,7 +631,7 @@ NSUInteger length = [characters length]; // Fallback unicode character handler used if IME is not active. - if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]))) { + if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]))) { Char16String text; text.resize([characters length] + 1); [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])]; @@ -634,28 +641,28 @@ for (int i = 0; i < u32text.length(); i++) { const char32_t codepoint = u32text[i]; - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = false; ke.echo = [event isARepeat]; - ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]); - ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]); + ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]); + ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]); ke.raw = true; ke.unicode = codepoint; ds->push_to_key_event_buffer(ke); } } else { - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = false; ke.echo = [event isARepeat]; - ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]); - ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]); + ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]); + ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]); ke.raw = true; ke.unicode = 0; @@ -667,12 +674,12 @@ // MARK: Scroll and pan - (void)processScrollEvent:(NSEvent *)event button:(MouseButton)button factor:(double)factor { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); MouseButton mask = mouse_button_to_mask(button); Ref<InputEventMouseButton> sc; @@ -706,12 +713,12 @@ } - (void)processPanEvent:(NSEvent *)event dx:(double)dx dy:(double)dy { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); Ref<InputEventPanGesture> pg; pg.instantiate(); @@ -725,12 +732,12 @@ } - (void)scrollWheel:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->update_mouse_pos(wd, [event locationInWindow]); double delta_x = [event scrollingDeltaX]; diff --git a/platform/osx/godot_main_osx.mm b/platform/macos/godot_main_macos.mm index 053a7f4a1d..66071f1404 100644 --- a/platform/osx/godot_main_osx.mm +++ b/platform/macos/godot_main_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_main_osx.mm */ +/* godot_main_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,7 +30,7 @@ #include "main/main.h" -#include "os_osx.h" +#include "os_macos.h" #include <string.h> #include <unistd.h> @@ -68,22 +68,17 @@ int main(int argc, char **argv) { printf("Current path: %s\n", cwd); #endif - OS_OSX os; + OS_MacOS os; Error err; // We must override main when testing is enabled. TEST_MAIN_OVERRIDE - if (os.get_open_with_filename() != "") { - char *argv_c = (char *)malloc(os.get_open_with_filename().utf8().size()); - memcpy(argv_c, os.get_open_with_filename().utf8().get_data(), os.get_open_with_filename().utf8().size()); - err = Main::setup(argv[0], 1, &argv_c); - free(argv_c); - } else { - err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]); - } + err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]); - if (err != OK) { + if (err == ERR_HELP) { // Returned by --help and --version, so success. + return 0; + } else if (err != OK) { return 255; } diff --git a/platform/osx/godot_menu_item.h b/platform/macos/godot_menu_item.h index 2c12897f10..2c12897f10 100644 --- a/platform/osx/godot_menu_item.h +++ b/platform/macos/godot_menu_item.h diff --git a/platform/osx/godot_window.h b/platform/macos/godot_window.h index 16ff101142..9fc5599e86 100644 --- a/platform/osx/godot_window.h +++ b/platform/macos/godot_window.h @@ -44,4 +44,4 @@ @end -#endif //GODOT_WINDOW_H +#endif // GODOT_WINDOW_H diff --git a/platform/osx/godot_window.mm b/platform/macos/godot_window.mm index d43853a94b..e205e7546d 100644 --- a/platform/osx/godot_window.mm +++ b/platform/macos/godot_window.mm @@ -30,7 +30,7 @@ #include "godot_window.h" -#include "display_server_osx.h" +#include "display_server_macos.h" @implementation GodotWindow @@ -40,29 +40,29 @@ return self; } -- (void)setWindowID:(DisplayServerOSX::WindowID)wid { +- (void)setWindowID:(DisplayServerMacOS::WindowID)wid { window_id = wid; } - (BOOL)canBecomeKeyWindow { // Required for NSWindowStyleMaskBorderless windows. - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return YES; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); return !wd.no_focus && !wd.is_popup; } - (BOOL)canBecomeMainWindow { // Required for NSWindowStyleMaskBorderless windows. - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return YES; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); return !wd.no_focus && !wd.is_popup; } diff --git a/platform/osx/godot_window_delegate.h b/platform/macos/godot_window_delegate.h index 8a1f681fcd..98c226aa2f 100644 --- a/platform/osx/godot_window_delegate.h +++ b/platform/macos/godot_window_delegate.h @@ -44,4 +44,4 @@ @end -#endif //GODOT_WINDOW_DELEGATE_H +#endif // GODOT_WINDOW_DELEGATE_H diff --git a/platform/osx/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm index 521127f01b..e1e88274f0 100644 --- a/platform/osx/godot_window_delegate.mm +++ b/platform/macos/godot_window_delegate.mm @@ -30,7 +30,7 @@ #include "godot_window_delegate.h" -#include "display_server_osx.h" +#include "display_server_macos.h" @implementation GodotWindowDelegate @@ -39,42 +39,42 @@ } - (BOOL)windowShouldClose:(id)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return YES; } - ds->send_window_event(ds->get_window(window_id), DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + ds->send_window_event(ds->get_window(window_id), DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); return NO; } - (void)windowWillClose:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } ds->popup_close(window_id); - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); while (wd.transient_children.size()) { - ds->window_set_transient(*wd.transient_children.begin(), DisplayServerOSX::INVALID_WINDOW_ID); + ds->window_set_transient(*wd.transient_children.begin(), DisplayServerMacOS::INVALID_WINDOW_ID); } - if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) { - ds->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID); + if (wd.transient_parent != DisplayServerMacOS::INVALID_WINDOW_ID) { + ds->window_set_transient(window_id, DisplayServerMacOS::INVALID_WINDOW_ID); } ds->window_destroy(window_id); } - (void)windowDidEnterFullScreen:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); wd.fullscreen = true; // Reset window size limits. [wd.window_object setContentMinSize:NSMakeSize(0, 0)]; @@ -85,12 +85,12 @@ } - (void)windowDidExitFullScreen:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); wd.fullscreen = false; // Set window size limits. @@ -119,12 +119,12 @@ } - (void)windowDidChangeBackingProperties:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); CGFloat new_scale_factor = [wd.window_object backingScaleFactor]; CGFloat old_scale_factor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; @@ -137,7 +137,7 @@ wd.size.width = content_rect.size.width * scale; wd.size.height = content_rect.size.height * scale; - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_DPI_CHANGE); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_DPI_CHANGE); CALayer *layer = [wd.window_view layer]; if (layer) { @@ -150,26 +150,26 @@ } - (void)windowWillStartLiveResize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->set_is_resizing(true); } } - (void)windowDidEndLiveResize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->set_is_resizing(false); } } - (void)windowDidResize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); const NSRect content_rect = [wd.window_view frame]; const float scale = ds->screen_get_max_scale(); wd.size.width = content_rect.size.width * scale; @@ -192,12 +192,12 @@ } - (void)windowDidMove:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->release_pressed_events(); if (!wd.rect_changed_callback.is_null()) { @@ -210,12 +210,12 @@ } - (void)windowDidBecomeKey:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (ds->mouse_get_mode() == DisplayServer::MOUSE_MODE_CAPTURED) { const NSRect content_rect = [wd.window_view frame]; @@ -228,43 +228,43 @@ } ds->set_last_focused_window(window_id); - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN); } - (void)windowDidResignKey:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->release_pressed_events(); - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT); } - (void)windowDidMiniaturize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->release_pressed_events(); - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT); } - (void)windowDidDeminiaturize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->set_last_focused_window(window_id); - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN); } @end diff --git a/platform/osx/joypad_osx.cpp b/platform/macos/joypad_macos.cpp index be9567e17c..1ddcfec1b5 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/macos/joypad_macos.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joypad_osx.cpp */ +/* joypad_macos.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "joypad_osx.h" +#include "joypad_macos.h" #include <machine/endian.h> #define GODOT_JOY_LOOP_RUN_MODE CFSTR("GodotJoypad") -static JoypadOSX *self = nullptr; +static JoypadMacOS *self = nullptr; joypad::joypad() { ff_constant_force.lMagnitude = 10000; @@ -235,7 +235,7 @@ static bool is_joypad(IOHIDDeviceRef p_device_ref) { return true; } -void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { +void JoypadMacOS::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { if (p_res != kIOReturnSuccess || have_device(p_device)) { return; } @@ -258,7 +258,7 @@ void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { IOHIDDeviceScheduleWithRunLoop(p_device, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); } -void JoypadOSX::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) { +void JoypadMacOS::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) { int device = get_joy_ref(p_device); ERR_FAIL_COND(device == -1); @@ -278,7 +278,7 @@ static String _hex_str(uint8_t p_byte) { return ret; } -bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { +bool JoypadMacOS::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { p_joy->device_ref = p_device_ref; // Get device name. String name; @@ -445,7 +445,7 @@ static HatMask process_hat_value(int p_min, int p_max, int p_value, bool p_offse return hat_value; } -void JoypadOSX::poll_joypads() const { +void JoypadMacOS::poll_joypads() const { while (CFRunLoopRunInMode(GODOT_JOY_LOOP_RUN_MODE, 0, TRUE) == kCFRunLoopRunHandledSource) { // No-op. Pending callbacks will fire. } @@ -456,7 +456,7 @@ static float axis_correct(int p_value, int p_min, int p_max) { return 2.0f * (p_value - p_min) / (p_max - p_min) - 1.0f; } -void JoypadOSX::process_joypads() { +void JoypadMacOS::process_joypads() { poll_joypads(); for (int i = 0; i < device_list.size(); i++) { @@ -494,7 +494,7 @@ void JoypadOSX::process_joypads() { } } -void JoypadOSX::joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp) { +void JoypadMacOS::joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp) { joypad *joy = &device_list.write[get_joy_index(p_id)]; joy->ff_timestamp = p_timestamp; joy->ff_effect.dwDuration = p_duration * FF_SECONDS; @@ -503,13 +503,13 @@ void JoypadOSX::joypad_vibration_start(int p_id, float p_magnitude, float p_dura FFEffectStart(joy->ff_object, 1, 0); } -void JoypadOSX::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { +void JoypadMacOS::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { joypad *joy = &device_list.write[get_joy_index(p_id)]; joy->ff_timestamp = p_timestamp; FFEffectStop(joy->ff_object); } -int JoypadOSX::get_joy_index(int p_id) const { +int JoypadMacOS::get_joy_index(int p_id) const { for (int i = 0; i < device_list.size(); i++) { if (device_list[i].id == p_id) { return i; @@ -518,7 +518,7 @@ int JoypadOSX::get_joy_index(int p_id) const { return -1; } -int JoypadOSX::get_joy_ref(IOHIDDeviceRef p_device) const { +int JoypadMacOS::get_joy_ref(IOHIDDeviceRef p_device) const { for (int i = 0; i < device_list.size(); i++) { if (device_list[i].device_ref == p_device) { return i; @@ -527,7 +527,7 @@ int JoypadOSX::get_joy_ref(IOHIDDeviceRef p_device) const { return -1; } -bool JoypadOSX::have_device(IOHIDDeviceRef p_device) const { +bool JoypadMacOS::have_device(IOHIDDeviceRef p_device) const { for (int i = 0; i < device_list.size(); i++) { if (device_list[i].device_ref == p_device) { return true; @@ -561,7 +561,7 @@ static CFDictionaryRef create_match_dictionary(const UInt32 page, const UInt32 u return retval; } -void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const { +void JoypadMacOS::config_hid_manager(CFArrayRef p_matching_array) const { CFRunLoopRef runloop = CFRunLoopGetCurrent(); IOReturn ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); ERR_FAIL_COND(ret != kIOReturnSuccess); @@ -576,7 +576,7 @@ void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const { } } -JoypadOSX::JoypadOSX(Input *in) { +JoypadMacOS::JoypadMacOS(Input *in) { self = this; input = in; @@ -604,7 +604,7 @@ JoypadOSX::JoypadOSX(Input *in) { } } -JoypadOSX::~JoypadOSX() { +JoypadMacOS::~JoypadMacOS() { for (int i = 0; i < device_list.size(); i++) { device_list.write[i].free(); } diff --git a/platform/osx/joypad_osx.h b/platform/macos/joypad_macos.h index 3f89048ce6..4b14fed6d5 100644 --- a/platform/osx/joypad_osx.h +++ b/platform/macos/joypad_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joypad_osx.h */ +/* joypad_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JOYPADOSX_H -#define JOYPADOSX_H +#ifndef JOYPAD_MACOS_H +#define JOYPAD_MACOS_H #ifdef MACOS_10_0_4 #import <IOKit/hidsystem/IOHIDUsageTables.h> @@ -88,7 +88,7 @@ struct joypad { joypad(); }; -class JoypadOSX { +class JoypadMacOS { enum { JOYPADS_MAX = 16, }; @@ -117,8 +117,8 @@ public: void _device_added(IOReturn p_res, IOHIDDeviceRef p_device); void _device_removed(IOReturn p_res, IOHIDDeviceRef p_device); - JoypadOSX(Input *in); - ~JoypadOSX(); + JoypadMacOS(Input *in); + ~JoypadMacOS(); }; -#endif // JOYPADOSX_H +#endif // JOYPAD_MACOS_H diff --git a/platform/osx/key_mapping_osx.h b/platform/macos/key_mapping_macos.h index 252cc907bb..fc5b791e44 100644 --- a/platform/osx/key_mapping_osx.h +++ b/platform/macos/key_mapping_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* key_mapping_osx.h */ +/* key_mapping_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef KEY_MAPPING_OSX_H -#define KEY_MAPPING_OSX_H +#ifndef KEY_MAPPING_MACOS_H +#define KEY_MAPPING_MACOS_H #include "core/os/keyboard.h" -class KeyMappingOSX { - KeyMappingOSX() {} +class KeyMappingMacOS { + KeyMappingMacOS() {} static bool is_numpad_key(unsigned int key); @@ -49,4 +49,4 @@ public: static unsigned int keycode_get_native_mask(Key p_keycode); }; -#endif // KEY_MAPPING_OSX_H +#endif // KEY_MAPPING_MACOS_H diff --git a/platform/osx/key_mapping_osx.mm b/platform/macos/key_mapping_macos.mm index 0bf6bc7d1c..f6cff7124b 100644 --- a/platform/osx/key_mapping_osx.mm +++ b/platform/macos/key_mapping_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* key_mapping_osx.mm */ +/* key_mapping_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "key_mapping_osx.h" +#include "key_mapping_macos.h" #import <Carbon/Carbon.h> #import <Cocoa/Cocoa.h> -bool KeyMappingOSX::is_numpad_key(unsigned int key) { +bool KeyMappingMacOS::is_numpad_key(unsigned int key) { static const unsigned int table[] = { 0x41, /* kVK_ANSI_KeypadDecimal */ 0x43, /* kVK_ANSI_KeypadMultiply */ @@ -65,7 +65,7 @@ bool KeyMappingOSX::is_numpad_key(unsigned int key) { } // Keyboard symbol translation table. -static const Key _osx_to_godot_table[128] = { +static const Key _macos_to_godot_table[128] = { /* 00 */ Key::A, /* 01 */ Key::S, /* 02 */ Key::D, @@ -197,18 +197,18 @@ static const Key _osx_to_godot_table[128] = { }; // Translates a OS X keycode to a Godot keycode. -Key KeyMappingOSX::translate_key(unsigned int key) { +Key KeyMappingMacOS::translate_key(unsigned int key) { if (key >= 128) { return Key::UNKNOWN; } - return _osx_to_godot_table[key]; + return _macos_to_godot_table[key]; } -// Translates a Godot keycode back to a OSX keycode. -unsigned int KeyMappingOSX::unmap_key(Key key) { +// Translates a Godot keycode back to a macOS keycode. +unsigned int KeyMappingMacOS::unmap_key(Key key) { for (int i = 0; i <= 126; i++) { - if (_osx_to_godot_table[i] == key) { + if (_macos_to_godot_table[i] == key) { return i; } } @@ -279,7 +279,7 @@ static const _KeyCodeMap _keycodes[55] = { }; // Remap key according to current keyboard layout. -Key KeyMappingOSX::remap_key(unsigned int key, unsigned int state) { +Key KeyMappingMacOS::remap_key(unsigned int key, unsigned int state) { if (is_numpad_key(key)) { return translate_key(key); } @@ -463,7 +463,7 @@ static const _KeyCodeText _native_keycodes[] = { /* clang-format on */ }; -String KeyMappingOSX::keycode_get_native_string(Key p_keycode) { +String KeyMappingMacOS::keycode_get_native_string(Key p_keycode) { const _KeyCodeText *kct = &_native_keycodes[0]; while (kct->text) { @@ -475,7 +475,7 @@ String KeyMappingOSX::keycode_get_native_string(Key p_keycode) { return String(); } -unsigned int KeyMappingOSX::keycode_get_native_mask(Key p_keycode) { +unsigned int KeyMappingMacOS::keycode_get_native_mask(Key p_keycode) { unsigned int mask = 0; if ((p_keycode & KeyModifierMask::CTRL) != Key::NONE) { mask |= NSEventModifierFlagControl; diff --git a/platform/osx/logo.png b/platform/macos/logo.png Binary files differindex b5a660b165..b5a660b165 100644 --- a/platform/osx/logo.png +++ b/platform/macos/logo.png diff --git a/platform/osx/osx_terminal_logger.h b/platform/macos/macos_terminal_logger.h index 8413509c4b..a811a5cbaf 100644 --- a/platform/osx/osx_terminal_logger.h +++ b/platform/macos/macos_terminal_logger.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* osx_terminal_logger.h */ +/* macos_terminal_logger.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OSX_TERMINAL_LOGGER_H -#define OSX_TERMINAL_LOGGER_H +#ifndef MACOS_TERMINAL_LOGGER_H +#define MACOS_TERMINAL_LOGGER_H -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED #include "core/io/logger.h" -class OSXTerminalLogger : public StdLogger { +class MacOSTerminalLogger : public StdLogger { public: virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, ErrorType p_type = ERR_ERROR) override; }; -#endif // OSX_ENABLED -#endif // OSX_TERMINAL_LOGGER_H +#endif // MACOS_ENABLED + +#endif // MACOS_TERMINAL_LOGGER_H diff --git a/platform/osx/osx_terminal_logger.mm b/platform/macos/macos_terminal_logger.mm index 48e26f42bf..b5ea2938ee 100644 --- a/platform/osx/osx_terminal_logger.mm +++ b/platform/macos/macos_terminal_logger.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* osx_terminal_logger.mm */ +/* macos_terminal_logger.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "osx_terminal_logger.h" +#include "macos_terminal_logger.h" -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED #include <os/log.h> -void OSXTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) { +void MacOSTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) { if (!should_log(true)) { return; } @@ -79,4 +79,4 @@ void OSXTerminalLogger::log_error(const char *p_function, const char *p_file, in } } -#endif // OSX_ENABLED +#endif // MACOS_ENABLED diff --git a/platform/osx/os_osx.h b/platform/macos/os_macos.h index e4ec411c96..a6c23ab71e 100644 --- a/platform/osx/os_osx.h +++ b/platform/macos/os_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_osx.h */ +/* os_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,21 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OS_OSX_H -#define OS_OSX_H +#ifndef OS_MACOS_H +#define OS_MACOS_H #include "core/input/input.h" -#include "crash_handler_osx.h" +#include "crash_handler_macos.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" #include "drivers/coremidi/midi_driver_coremidi.h" #include "drivers/unix/os_unix.h" -#include "joypad_osx.h" +#include "joypad_macos.h" #include "servers/audio_server.h" -class OS_OSX : public OS_Unix { +class OS_MacOS : public OS_Unix { bool force_quit = false; - JoypadOSX *joypad_osx = nullptr; + JoypadMacOS *joypad_macos = nullptr; #ifdef COREAUDIO_ENABLED AudioDriverCoreAudio audio_driver; @@ -57,7 +57,7 @@ class OS_OSX : public OS_Unix { MainLoop *main_loop = nullptr; - String open_with_filename; + List<String> launch_service_args; static _FORCE_INLINE_ String get_framework_executable(const String &p_path); static void pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context); @@ -73,8 +73,8 @@ protected: virtual void delete_main_loop() override; public: - String get_open_with_filename() const; - void set_open_with_filename(const String &p_path); + virtual void set_cmdline_platform_args(const List<String> &p_args); + virtual List<String> get_cmdline_platform_args() const override; virtual String get_name() const override; @@ -113,8 +113,8 @@ public: void run(); - OS_OSX(); - ~OS_OSX(); + OS_MacOS(); + ~OS_MacOS(); }; -#endif +#endif // OS_MACOS_H diff --git a/platform/osx/os_osx.mm b/platform/macos/os_macos.mm index a8fa56e34b..2c6cd7de0b 100644 --- a/platform/osx/os_osx.mm +++ b/platform/macos/os_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_osx.mm */ +/* os_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "os_osx.h" +#include "os_macos.h" #include "core/version_generated.gen.h" #include "main/main.h" -#include "dir_access_osx.h" -#include "display_server_osx.h" +#include "dir_access_macos.h" +#include "display_server_macos.h" #include "godot_application.h" #include "godot_application_delegate.h" -#include "osx_terminal_logger.h" +#include "macos_terminal_logger.h" #include <dlfcn.h> #include <libproc.h> @@ -45,7 +45,7 @@ #include <os/log.h> #include <sys/sysctl.h> -_FORCE_INLINE_ String OS_OSX::get_framework_executable(const String &p_path) { +_FORCE_INLINE_ String OS_MacOS::get_framework_executable(const String &p_path) { // Append framework executable name, or return as is if p_path is not a framework. Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (da->dir_exists(p_path) && da->file_exists(p_path.plus_file(p_path.get_file().get_basename()))) { @@ -55,10 +55,10 @@ _FORCE_INLINE_ String OS_OSX::get_framework_executable(const String &p_path) { } } -void OS_OSX::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) { +void OS_MacOS::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) { // Prevent main loop from sleeping and redraw window during resize / modal popups. - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (get_singleton()->get_main_loop() && ds && (get_singleton()->get_render_thread_mode() != RENDER_SEPARATE_THREAD || !ds->get_is_resizing())) { Main::force_redraw(); if (!Main::is_iterating()) { // Avoid cyclic loop. @@ -69,13 +69,13 @@ void OS_OSX::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActi CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Prevent main loop from sleeping. } -void OS_OSX::initialize() { +void OS_MacOS::initialize() { crash_handler.initialize(); initialize_core(); } -String OS_OSX::get_processor_name() const { +String OS_MacOS::get_processor_name() const { char buffer[256]; size_t buffer_len = 256; if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, NULL, 0) == 0) { @@ -84,35 +84,35 @@ String OS_OSX::get_processor_name() const { ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string.")); } -void OS_OSX::initialize_core() { +void OS_MacOS::initialize_core() { OS_Unix::initialize_core(); - DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_RESOURCES); - DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_USERDATA); - DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_FILESYSTEM); + DirAccess::make_default<DirAccessMacOS>(DirAccess::ACCESS_RESOURCES); + DirAccess::make_default<DirAccessMacOS>(DirAccess::ACCESS_USERDATA); + DirAccess::make_default<DirAccessMacOS>(DirAccess::ACCESS_FILESYSTEM); } -void OS_OSX::finalize() { +void OS_MacOS::finalize() { #ifdef COREMIDI_ENABLED midi_driver.close(); #endif delete_main_loop(); - if (joypad_osx) { - memdelete(joypad_osx); + if (joypad_macos) { + memdelete(joypad_macos); } } -void OS_OSX::initialize_joypads() { - joypad_osx = memnew(JoypadOSX(Input::get_singleton())); +void OS_MacOS::initialize_joypads() { + joypad_macos = memnew(JoypadMacOS(Input::get_singleton())); } -void OS_OSX::set_main_loop(MainLoop *p_main_loop) { +void OS_MacOS::set_main_loop(MainLoop *p_main_loop) { main_loop = p_main_loop; } -void OS_OSX::delete_main_loop() { +void OS_MacOS::delete_main_loop() { if (!main_loop) { return; } @@ -121,19 +121,19 @@ void OS_OSX::delete_main_loop() { main_loop = nullptr; } -String OS_OSX::get_open_with_filename() const { - return open_with_filename; +void OS_MacOS::set_cmdline_platform_args(const List<String> &p_args) { + launch_service_args = p_args; } -void OS_OSX::set_open_with_filename(const String &p_path) { - open_with_filename = p_path; +List<String> OS_MacOS::get_cmdline_platform_args() const { + return launch_service_args; } -String OS_OSX::get_name() const { +String OS_MacOS::get_name() const { return "macOS"; } -void OS_OSX::alert(const String &p_alert, const String &p_title) { +void OS_MacOS::alert(const String &p_alert, const String &p_title) { NSAlert *window = [[NSAlert alloc] init]; NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()]; NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()]; @@ -150,7 +150,7 @@ void OS_OSX::alert(const String &p_alert, const String &p_title) { } } -Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { +Error OS_MacOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = get_framework_executable(p_path); if (!FileAccess::exists(path)) { @@ -173,11 +173,11 @@ Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, return OK; } -MainLoop *OS_OSX::get_main_loop() const { +MainLoop *OS_MacOS::get_main_loop() const { return main_loop; } -String OS_OSX::get_config_path() const { +String OS_MacOS::get_config_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_CONFIG_HOME")) { if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { @@ -192,7 +192,7 @@ String OS_OSX::get_config_path() const { return "."; } -String OS_OSX::get_data_path() const { +String OS_MacOS::get_data_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_DATA_HOME")) { if (get_environment("XDG_DATA_HOME").is_absolute_path()) { @@ -204,7 +204,7 @@ String OS_OSX::get_data_path() const { return get_config_path(); } -String OS_OSX::get_cache_path() const { +String OS_MacOS::get_cache_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_CACHE_HOME")) { if (get_environment("XDG_CACHE_HOME").is_absolute_path()) { @@ -219,7 +219,7 @@ String OS_OSX::get_cache_path() const { return get_config_path(); } -String OS_OSX::get_bundle_resource_dir() const { +String OS_MacOS::get_bundle_resource_dir() const { String ret; NSBundle *main = [NSBundle mainBundle]; @@ -230,7 +230,7 @@ String OS_OSX::get_bundle_resource_dir() const { return ret; } -String OS_OSX::get_bundle_icon_path() const { +String OS_MacOS::get_bundle_icon_path() const { String ret; NSBundle *main = [NSBundle mainBundle]; @@ -244,11 +244,11 @@ String OS_OSX::get_bundle_icon_path() const { } // Get properly capitalized engine name for system paths -String OS_OSX::get_godot_dir_name() const { +String OS_MacOS::get_godot_dir_name() const { return String(VERSION_SHORT_NAME).capitalize(); } -String OS_OSX::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { +String OS_MacOS::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { NSSearchPathDirectory id; bool found = true; @@ -287,7 +287,7 @@ String OS_OSX::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { return ret; } -Error OS_OSX::shell_open(String p_uri) { +Error OS_MacOS::shell_open(String p_uri) { NSString *string = [NSString stringWithUTF8String:p_uri.utf8().get_data()]; NSURL *uri = [[NSURL alloc] initWithString:string]; // Escape special characters in filenames @@ -298,12 +298,12 @@ Error OS_OSX::shell_open(String p_uri) { return OK; } -String OS_OSX::get_locale() const { +String OS_MacOS::get_locale() const { NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0]; return String([locale_code UTF8String]).replace("-", "_"); } -String OS_OSX::get_executable_path() const { +String OS_MacOS::get_executable_path() const { char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; int pid = getpid(); pid_t ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf)); @@ -317,7 +317,7 @@ String OS_OSX::get_executable_path() const { } } -Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { +Error OS_MacOS::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { // Use NSWorkspace if path is an .app bundle. NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())]; NSBundle *bundle = [NSBundle bundleWithURL:url]; @@ -375,7 +375,7 @@ Error OS_OSX::create_process(const String &p_path, const List<String> &p_argumen } } -Error OS_OSX::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) { +Error OS_MacOS::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) { // If executable is bundled, always execute editor instances as an app bundle to ensure app window is registered and activated correctly. NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; if (nsappname != nil) { @@ -387,7 +387,7 @@ Error OS_OSX::create_instance(const List<String> &p_arguments, ProcessID *r_chil } } -String OS_OSX::get_unique_id() const { +String OS_MacOS::get_unique_id() const { static String serial_number; if (serial_number.is_empty()) { @@ -412,19 +412,19 @@ String OS_OSX::get_unique_id() const { return serial_number; } -bool OS_OSX::_check_internal_feature_support(const String &p_feature) { +bool OS_MacOS::_check_internal_feature_support(const String &p_feature) { return p_feature == "pc"; } -void OS_OSX::disable_crash_handler() { +void OS_MacOS::disable_crash_handler() { crash_handler.disable(); } -bool OS_OSX::is_disable_crash_handler() const { +bool OS_MacOS::is_disable_crash_handler() const { return crash_handler.is_disabled(); } -Error OS_OSX::move_to_trash(const String &p_path) { +Error OS_MacOS::move_to_trash(const String &p_path) { NSFileManager *fm = [NSFileManager defaultManager]; NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())]; NSError *err; @@ -437,7 +437,7 @@ Error OS_OSX::move_to_trash(const String &p_path) { return OK; } -void OS_OSX::run() { +void OS_MacOS::run() { force_quit = false; if (!main_loop) { @@ -452,7 +452,7 @@ void OS_OSX::run() { if (DisplayServer::get_singleton()) { DisplayServer::get_singleton()->process_events(); // Get rid of pending events. } - joypad_osx->process_joypads(); + joypad_macos->process_joypads(); if (Main::iteration()) { quit = true; @@ -465,19 +465,19 @@ void OS_OSX::run() { main_loop->finalize(); } -OS_OSX::OS_OSX() { +OS_MacOS::OS_MacOS() { main_loop = nullptr; force_quit = false; Vector<Logger *> loggers; - loggers.push_back(memnew(OSXTerminalLogger)); + loggers.push_back(memnew(MacOSTerminalLogger)); _set_logger(memnew(CompositeLogger(loggers))); #ifdef COREAUDIO_ENABLED AudioDriverManager::add_driver(&audio_driver); #endif - DisplayServerOSX::register_osx_driver(); + DisplayServerMacOS::register_macos_driver(); // Implicitly create shared NSApplication instance. [GodotApplication sharedApplication]; @@ -518,7 +518,7 @@ OS_OSX::OS_OSX() { [NSApp activateIgnoringOtherApps:YES]; } -OS_OSX::~OS_OSX() { +OS_MacOS::~OS_MacOS() { CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); CFRelease(pre_wait_observer); } diff --git a/platform/osx/platform_config.h b/platform/macos/platform_config.h index e114606b82..e114606b82 100644 --- a/platform/osx/platform_config.h +++ b/platform/macos/platform_config.h diff --git a/platform/osx/platform_osx_builders.py b/platform/macos/platform_macos_builders.py index 953ed479db..3a1cc92bd2 100644 --- a/platform/osx/platform_osx_builders.py +++ b/platform/macos/platform_macos_builders.py @@ -7,7 +7,7 @@ import os from platform_methods import subprocess_main -def make_debug_osx(target, source, env): +def make_debug_macos(target, source, env): if env["macports_clang"] != "no": mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") mpclangver = env["macports_clang"] diff --git a/platform/osx/tts_osx.h b/platform/macos/tts_macos.h index 449418e48f..344676868a 100644 --- a/platform/osx/tts_osx.h +++ b/platform/macos/tts_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* tts_osx.h */ +/* tts_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TTS_OSX_H -#define TTS_OSX_H +#ifndef TTS_MACOS_H +#define TTS_MACOS_H #include "core/string/ustring.h" #include "core/templates/list.h" @@ -45,7 +45,7 @@ #import <AVFoundation/AVFoundation.h> #endif -@interface TTS_OSX : NSObject <AVSpeechSynthesizerDelegate> { +@interface TTS_MacOS : NSObject <AVSpeechSynthesizerDelegate> { // AVSpeechSynthesizer bool speaking; HashMap<id, int> ids; @@ -68,4 +68,4 @@ - (Array)getVoices; @end -#endif // TTS_OSX_H +#endif // TTS_MACOS_H diff --git a/platform/osx/tts_osx.mm b/platform/macos/tts_macos.mm index e6a5236cd9..3c101b9531 100644 --- a/platform/osx/tts_osx.mm +++ b/platform/macos/tts_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* tts_osx.mm */ +/* tts_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "tts_osx.h" +#include "tts_macos.h" -@implementation TTS_OSX +@implementation TTS_MacOS - (id)init { self = [super init]; diff --git a/platform/osx/vulkan_context_osx.h b/platform/macos/vulkan_context_macos.h index ade0f4a4c9..579c42b042 100644 --- a/platform/osx/vulkan_context_osx.h +++ b/platform/macos/vulkan_context_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* vulkan_context_osx.h */ +/* vulkan_context_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VULKAN_DEVICE_OSX_H -#define VULKAN_DEVICE_OSX_H +#ifndef VULKAN_CONTEXT_MACOS_H +#define VULKAN_CONTEXT_MACOS_H #include "drivers/vulkan/vulkan_context.h" #import <AppKit/AppKit.h> -class VulkanContextOSX : public VulkanContext { +class VulkanContextMacOS : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height); - VulkanContextOSX(); - ~VulkanContextOSX(); + VulkanContextMacOS(); + ~VulkanContextMacOS(); }; -#endif // VULKAN_DEVICE_OSX_H +#endif // VULKAN_CONTEXT_MACOS_H diff --git a/platform/osx/vulkan_context_osx.mm b/platform/macos/vulkan_context_macos.mm index bdabc24c28..cf317f3c68 100644 --- a/platform/osx/vulkan_context_osx.mm +++ b/platform/macos/vulkan_context_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* vulkan_context_osx.mm */ +/* vulkan_context_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,18 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "vulkan_context_osx.h" +#include "vulkan_context_macos.h" #ifdef USE_VOLK #include <volk.h> #else #include <vulkan/vulkan.h> #endif -const char *VulkanContextOSX::_get_platform_surface_extension() const { +const char *VulkanContextMacOS::_get_platform_surface_extension() const { return VK_MVK_MACOS_SURFACE_EXTENSION_NAME; } -Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height) { +Error VulkanContextMacOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height) { VkMacOSSurfaceCreateInfoMVK createInfo; createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = nullptr; @@ -52,8 +52,8 @@ Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, Displ return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } -VulkanContextOSX::VulkanContextOSX() { +VulkanContextMacOS::VulkanContextMacOS() { } -VulkanContextOSX::~VulkanContextOSX() { +VulkanContextMacOS::~VulkanContextMacOS() { } diff --git a/platform/osx/SCsub b/platform/osx/SCsub deleted file mode 100644 index 3a4c95613d..0000000000 --- a/platform/osx/SCsub +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -from platform_methods import run_in_subprocess -import platform_osx_builders - -files = [ - "os_osx.mm", - "godot_application.mm", - "godot_application_delegate.mm", - "crash_handler_osx.mm", - "osx_terminal_logger.mm", - "display_server_osx.mm", - "godot_content_view.mm", - "godot_window_delegate.mm", - "godot_window.mm", - "key_mapping_osx.mm", - "godot_main_osx.mm", - "dir_access_osx.mm", - "tts_osx.mm", - "joypad_osx.cpp", - "vulkan_context_osx.mm", - "gl_manager_osx_legacy.mm", -] - -prog = env.add_program("#bin/godot", files) - -if env["debug_symbols"] and env["separate_debug_symbols"]: - env.AddPostAction(prog, run_in_subprocess(platform_osx_builders.make_debug_osx)) diff --git a/platform/register_platform_apis.h b/platform/register_platform_apis.h index 8b6d23a7a4..9dd90d9b20 100644 --- a/platform/register_platform_apis.h +++ b/platform/register_platform_apis.h @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef REGISTER_APIS_H -#define REGISTER_APIS_H +#ifndef REGISTER_PLATFORM_APIS_H +#define REGISTER_PLATFORM_APIS_H void register_platform_apis(); void unregister_platform_apis(); -#endif +#endif // REGISTER_PLATFORM_APIS_H diff --git a/platform/uwp/app_uwp.h b/platform/uwp/app_uwp.h index 9aadcfac75..82ad3ca01a 100644 --- a/platform/uwp/app_uwp.h +++ b/platform/uwp/app_uwp.h @@ -112,4 +112,5 @@ namespace GodotUWP } /* clang-format on */ + #endif // APP_UWP_H diff --git a/platform/uwp/export/app_packager.h b/platform/uwp/export/app_packager.h index dc5a5259ec..18db3eb806 100644 --- a/platform/uwp/export/app_packager.h +++ b/platform/uwp/export/app_packager.h @@ -40,7 +40,7 @@ #include "core/io/zip_io.h" #include "core/object/class_db.h" #include "core/version.h" -#include "editor/editor_export.h" +#include "editor/export/editor_export_platform.h" #include "thirdparty/minizip/unzip.h" #include "thirdparty/minizip/zip.h" @@ -146,4 +146,4 @@ public: ~AppxPackager(); }; -#endif +#endif // UWP_APP_PACKAGER_H diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp index 01683c656c..19b43d50be 100644 --- a/platform/uwp/export/export_plugin.cpp +++ b/platform/uwp/export/export_plugin.cpp @@ -503,7 +503,5 @@ void EditorExportPlatformUWP::resolve_platform_feature_priorities(const Ref<Edit } EditorExportPlatformUWP::EditorExportPlatformUWP() { - Ref<Image> img = memnew(Image(_uwp_logo)); - logo.instantiate(); - logo->create_from_image(img); + logo = ImageTexture::create_from_image(memnew(Image(_uwp_logo))); } diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h index d92687075c..c1a1f8a935 100644 --- a/platform/uwp/export/export_plugin.h +++ b/platform/uwp/export/export_plugin.h @@ -39,9 +39,9 @@ #include "core/io/zip_io.h" #include "core/object/class_db.h" #include "core/version.h" -#include "editor/editor_export.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" +#include "editor/export/editor_export_platform.h" #include "thirdparty/minizip/unzip.h" #include "thirdparty/minizip/zip.h" @@ -446,4 +446,4 @@ public: EditorExportPlatformUWP(); }; -#endif +#endif // UWP_EXPORT_PLUGIN_H diff --git a/platform/uwp/joypad_uwp.h b/platform/uwp/joypad_uwp.h index 0869f1961d..81f84152b9 100644 --- a/platform/uwp/joypad_uwp.h +++ b/platform/uwp/joypad_uwp.h @@ -78,4 +78,4 @@ private: void joypad_vibration_stop(int p_device, uint64_t p_timestamp); }; -#endif +#endif // JOYPAD_UWP_H diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 1614bfdcc3..f37759c66f 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -557,6 +557,7 @@ uint64_t OS_UWP::get_ticks_usec() const { void OS_UWP::process_events() { joypad->process_controllers(); process_key_events(); + input->flush_buffered_events(); } void OS_UWP::process_key_events() { diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index bddf63ff18..b9d035ff41 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -252,4 +252,4 @@ public: ~OS_UWP(); }; -#endif +#endif // OS_UWP_H diff --git a/platform/windows/detect.py b/platform/windows/detect.py index b82fe5e7ad..6a7caf4656 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -198,7 +198,6 @@ def configure_msvc(env, manual_msvc_config): elif env["target"] == "debug": env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"]) # Allow big objects. Only needed for debug, see MinGW branch for rationale. - env.AppendUnique(CCFLAGS=["/bigobj"]) env.Append(LINKFLAGS=["/DEBUG"]) if env["debug_symbols"]: @@ -221,6 +220,10 @@ def configure_msvc(env, manual_msvc_config): env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"]) env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding. env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++ + # Once it was thought that only debug builds would be too large, + # but this has recently stopped being true. See the mingw function + # for notes on why this shouldn't be enabled for gcc + env.AppendUnique(CCFLAGS=["/bigobj"]) if manual_msvc_config: # should be automatic if SCons found it if os.getenv("WindowsSdkDir") is not None: diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 998b0882b3..f9988b23bc 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -656,7 +656,9 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { void DisplayServerWindows::gl_window_make_current(DisplayServer::WindowID p_window_id) { #if defined(GLES3_ENABLED) - gl_manager->window_make_current(p_window_id); + if (gl_manager) { + gl_manager->window_make_current(p_window_id); + } #endif } @@ -2380,7 +2382,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } case WM_MOUSELEAVE: { old_invalid = true; - outside = true; + windows[window_id].mouse_outside = true; _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT); @@ -2490,6 +2492,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA windows[window_id].last_tilt = Vector2(); } + windows[window_id].last_pen_inverted = packet.pkStatus & TPS_INVERT; + POINT coords; GetCursorPos(&coords); ScreenToClient(windows[window_id].hWnd, &coords); @@ -2508,6 +2512,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_pressure(windows[window_id].last_pressure); mm->set_tilt(windows[window_id].last_tilt); + mm->set_pen_inverted(windows[window_id].last_pen_inverted); mm->set_button_mask(last_button_state); @@ -2607,7 +2612,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - if (outside) { + if (windows[window_id].mouse_outside) { // Mouse enter. if (mouse_mode != MOUSE_MODE_CAPTURED) { @@ -2617,7 +2622,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; cursor_set_shape(c); - outside = false; + windows[window_id].mouse_outside = false; // Once-off notification, must call again. track_mouse_leave_event(hWnd); @@ -2640,6 +2645,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if ((pen_info.penMask & PEN_MASK_TILT_X) && (pen_info.penMask & PEN_MASK_TILT_Y)) { mm->set_tilt(Vector2((float)pen_info.tiltX / 90, (float)pen_info.tiltY / 90)); } + mm->set_pen_inverted(pen_info.penFlags & (PEN_FLAG_INVERTED | PEN_FLAG_ERASER)); mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0); mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0); @@ -2707,7 +2713,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - if (outside) { + if (windows[window_id].mouse_outside) { // Mouse enter. if (mouse_mode != MOUSE_MODE_CAPTURED) { @@ -2717,7 +2723,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; cursor_set_shape(c); - outside = false; + windows[window_id].mouse_outside = false; // Once-off notification, must call again. track_mouse_leave_event(hWnd); @@ -2742,14 +2748,17 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } else { windows[window_id].last_tilt = Vector2(); windows[window_id].last_pressure = (wParam & MK_LBUTTON) ? 1.0f : 0.0f; + windows[window_id].last_pen_inverted = false; } } else { windows[window_id].last_tilt = Vector2(); windows[window_id].last_pressure = (wParam & MK_LBUTTON) ? 1.0f : 0.0f; + windows[window_id].last_pen_inverted = false; } mm->set_pressure(windows[window_id].last_pressure); mm->set_tilt(windows[window_id].last_tilt); + mm->set_pen_inverted(windows[window_id].last_pen_inverted); mm->set_button_mask(last_button_state); @@ -3360,8 +3369,8 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const if ((p_new_driver == "wintab") && wintab_available) { wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc); wd.wtlc.lcOptions |= CXO_MESSAGES; - wd.wtlc.lcPktData = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION; - wd.wtlc.lcMoveMask = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE; + wd.wtlc.lcPktData = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION; + wd.wtlc.lcMoveMask = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE; wd.wtlc.lcPktMode = 0; wd.wtlc.lcOutOrgX = 0; wd.wtlc.lcOutExtX = wd.wtlc.lcInExtX; @@ -3449,6 +3458,12 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, windows.erase(id); ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Windows OS window."); } + if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { + wd.fullscreen = true; + if (p_mode == WINDOW_MODE_FULLSCREEN) { + wd.multiwindow_fs = true; + } + } if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { wd.pre_fs_valid = true; } @@ -3484,8 +3499,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, if ((tablet_get_current_driver() == "wintab") && wintab_available) { wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc); wd.wtlc.lcOptions |= CXO_MESSAGES; - wd.wtlc.lcPktData = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION; - wd.wtlc.lcMoveMask = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE; + wd.wtlc.lcPktData = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION; + wd.wtlc.lcMoveMask = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE; wd.wtlc.lcPktMode = 0; wd.wtlc.lcOutOrgX = 0; wd.wtlc.lcOutExtX = wd.wtlc.lcInExtX; @@ -3599,8 +3614,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win old_invalid = true; mouse_mode = MOUSE_MODE_VISIBLE; - outside = true; - rendering_driver = p_rendering_driver; // Init TTS diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index fc89517774..ddbf674c64 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -82,10 +82,13 @@ #define DVC_ROTATION 18 #define CXO_MESSAGES 0x0004 +#define PK_STATUS 0x0002 #define PK_NORMAL_PRESSURE 0x0400 #define PK_TANGENT_PRESSURE 0x0800 #define PK_ORIENTATION 0x1000 +#define TPS_INVERT 0x0010 /* 1.1 */ + typedef struct tagLOGCONTEXTW { WCHAR lcName[40]; UINT lcOptions; @@ -137,6 +140,7 @@ typedef struct tagORIENTATION { } ORIENTATION; typedef struct tagPACKET { + int pkStatus; int pkNormalPressure; int pkTangentPressure; ORIENTATION pkOrientation; @@ -158,6 +162,14 @@ typedef UINT32 POINTER_FLAGS; typedef UINT32 PEN_FLAGS; typedef UINT32 PEN_MASK; +#ifndef PEN_FLAG_INVERTED +#define PEN_FLAG_INVERTED 0x00000002 +#endif + +#ifndef PEN_FLAG_ERASER +#define PEN_FLAG_ERASER 0x00000004 +#endif + #ifndef PEN_MASK_PRESSURE #define PEN_MASK_PRESSURE 0x00000001 #endif @@ -301,7 +313,6 @@ class DisplayServerWindows : public DisplayServer { int key_event_pos; bool old_invalid; - bool outside; int old_x, old_y; Point2i center; @@ -357,11 +368,13 @@ class DisplayServerWindows : public DisplayServer { int min_pressure; int max_pressure; bool tilt_supported; + bool pen_inverted = false; bool block_mm = false; int last_pressure_update; float last_pressure; Vector2 last_tilt; + bool last_pen_inverted = false; HBITMAP hBitmap; //DIB section for layered window uint8_t *dib_data = nullptr; @@ -373,6 +386,7 @@ class DisplayServerWindows : public DisplayServer { Size2 window_rect; Point2 last_pos; + bool mouse_outside = true; ObjectID instance_id; diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index 0fa2913218..20320470b8 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -30,6 +30,7 @@ #include "export.h" +#include "editor/export/editor_export.h" #include "export_plugin.h" void register_windows_exporter() { @@ -48,12 +49,7 @@ void register_windows_exporter() { Ref<EditorExportPlatformWindows> platform; platform.instantiate(); - - Ref<Image> img = memnew(Image(_windows_logo)); - Ref<ImageTexture> logo; - logo.instantiate(); - logo->create_from_image(img); - platform->set_logo(logo); + platform->set_logo(ImageTexture::create_from_image(memnew(Image(_windows_logo)))); platform->set_name("Windows Desktop"); platform->set_os_name("Windows"); diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h index 09399f2bee..1054e04b1e 100644 --- a/platform/windows/export/export.h +++ b/platform/windows/export/export.h @@ -33,4 +33,4 @@ void register_windows_exporter(); -#endif +#endif // WINDOWS_EXPORT_H diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 16c67345e0..45bfc761fe 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -104,7 +104,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } String EditorExportPlatformWindows::get_template_file_name(const String &p_target, const String &p_arch) const { - return "windows_" + p_arch + "_" + p_target + ".exe"; + return "windows_" + p_target + "_" + p_arch + ".exe"; } List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index 51f98365a9..b9e59829a0 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -33,8 +33,8 @@ #include "core/io/file_access.h" #include "core/os/os.h" -#include "editor/editor_export.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export_platform_pc.h" #include "platform/windows/logo.gen.h" class EditorExportPlatformWindows : public EditorExportPlatformPC { @@ -54,4 +54,4 @@ public: virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; }; -#endif +#endif // WINDOWS_EXPORT_PLUGIN_H diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index bb855e4ac8..899956d65a 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -41,10 +41,12 @@ <DisplayString Condition="type == Variant::AABB">{_data._aabb}</DisplayString> <DisplayString Condition="type == Variant::BASIS">{_data._basis}</DisplayString> <DisplayString Condition="type == Variant::TRANSFORM3D">{_data._transform}</DisplayString> + <DisplayString Condition="type == Variant::PROJECTION">{_data._projection}</DisplayString> <DisplayString Condition="type == Variant::STRING">{*(String *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::VECTOR4">{*(Vector4 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::QUATERNION">{*(Quaternion *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString> diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp index 8de3ef294a..72920d2816 100644 --- a/platform/windows/godot_windows.cpp +++ b/platform/windows/godot_windows.cpp @@ -166,6 +166,10 @@ int widechar_main(int argc, wchar_t **argv) { delete[] argv_utf8[i]; } delete[] argv_utf8; + + if (err == ERR_HELP) { // Returned by --help and --version, so success. + return 0; + } return 255; } diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 6f414c094c..b5423e62bf 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -951,9 +951,9 @@ 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::utf16((const char16_t *)(HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN); + HW_PROFILE_INFOA HwProfInfo; + ERR_FAIL_COND_V(!GetCurrentHwProfileA(&HwProfInfo), ""); + return String((HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN); } bool OS_Windows::_check_internal_feature_support(const String &p_feature) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index dc702c66e1..7d2d4ae705 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -185,4 +185,4 @@ public: ~OS_Windows(); }; -#endif +#endif // OS_WINDOWS_H diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h index e68f0125ca..d5950a129a 100644 --- a/platform/windows/vulkan_context_win.h +++ b/platform/windows/vulkan_context_win.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VULKAN_DEVICE_WIN_H -#define VULKAN_DEVICE_WIN_H +#ifndef VULKAN_CONTEXT_WIN_H +#define VULKAN_CONTEXT_WIN_H #include "drivers/vulkan/vulkan_context.h" @@ -46,4 +46,4 @@ public: ~VulkanContextWindows(); }; -#endif // VULKAN_DEVICE_WIN_H +#endif // VULKAN_CONTEXT_WIN_H diff --git a/platform/windows/windows_terminal_logger.h b/platform/windows/windows_terminal_logger.h index 1045f12201..348a49c845 100644 --- a/platform/windows/windows_terminal_logger.h +++ b/platform/windows/windows_terminal_logger.h @@ -44,4 +44,4 @@ public: #endif -#endif +#endif // WINDOWS_TERMINAL_LOGGER_H |