diff options
Diffstat (limited to 'platform/osx')
49 files changed, 0 insertions, 14572 deletions
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/osx/crash_handler_osx.h b/platform/osx/crash_handler_osx.h deleted file mode 100644 index 72938e5e0a..0000000000 --- a/platform/osx/crash_handler_osx.h +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************/ -/*  crash_handler_osx.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 CRASH_HANDLER_OSX_H -#define CRASH_HANDLER_OSX_H - -class CrashHandler { -	bool disabled; - -public: -	void initialize(); - -	void disable(); -	bool is_disabled() const { return disabled; }; - -	CrashHandler(); -	~CrashHandler(); -}; - -#endif // CRASH_HANDLER_OSX_H diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm deleted file mode 100644 index a798ba3b46..0000000000 --- a/platform/osx/crash_handler_osx.mm +++ /dev/null @@ -1,203 +0,0 @@ -/*************************************************************************/ -/*  crash_handler_osx.mm                                                 */ -/*************************************************************************/ -/*                       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 "crash_handler_osx.h" - -#include "core/config/project_settings.h" -#include "core/os/os.h" -#include "core/string/print_string.h" -#include "core/version.h" -#include "main/main.h" - -#include <string.h> -#include <unistd.h> - -#if defined(DEBUG_ENABLED) -#define CRASH_HANDLER_ENABLED 1 -#endif - -#ifdef CRASH_HANDLER_ENABLED -#include <cxxabi.h> -#include <dlfcn.h> -#include <execinfo.h> -#include <signal.h> -#include <stdlib.h> - -#include <mach-o/dyld.h> -#include <mach-o/getsect.h> - -static uint64_t load_address() { -	const struct segment_command_64 *cmd = getsegbyname("__TEXT"); -	char full_path[1024]; -	uint32_t size = sizeof(full_path); - -	if (cmd && !_NSGetExecutablePath(full_path, &size)) { -		uint32_t dyld_count = _dyld_image_count(); -		for (uint32_t i = 0; i < dyld_count; i++) { -			const char *image_name = _dyld_get_image_name(i); -			if (image_name && strncmp(image_name, full_path, 1024) == 0) { -				return cmd->vmaddr + _dyld_get_image_vmaddr_slide(i); -			} -		} -	} - -	return 0; -} - -static void handle_crash(int sig) { -	if (OS::get_singleton() == nullptr) { -		abort(); -	} - -	void *bt_buffer[256]; -	size_t size = backtrace(bt_buffer, 256); -	String _execpath = OS::get_singleton()->get_executable_path(); - -	String msg; -	const ProjectSettings *proj_settings = ProjectSettings::get_singleton(); -	if (proj_settings) { -		msg = proj_settings->get("debug/settings/crash_handler/message"); -	} - -	// Tell MainLoop about the crash. This can be handled by users too in Node. -	if (OS::get_singleton()->get_main_loop()) { -		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); -	} - -	// Dump the backtrace to stderr with a message to the user -	print_error("\n================================================================"); -	print_error(vformat("%s: Program crashed with signal %d", __FUNCTION__, sig)); - -	// Print the engine version just before, so that people are reminded to include the version in backtrace reports. -	if (String(VERSION_HASH).is_empty()) { -		print_error(vformat("Engine version: %s", VERSION_FULL_NAME)); -	} else { -		print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH)); -	} -	print_error(vformat("Dumping the backtrace. %s", msg)); -	char **strings = backtrace_symbols(bt_buffer, size); -	if (strings) { -		void *load_addr = (void *)load_address(); - -		for (size_t i = 1; i < size; i++) { -			char fname[1024]; -			Dl_info info; - -			snprintf(fname, 1024, "%s", strings[i]); - -			// Try to demangle the function name to provide a more readable one -			if (dladdr(bt_buffer[i], &info) && info.dli_sname) { -				if (info.dli_sname[0] == '_') { -					int status; -					char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status); - -					if (status == 0 && demangled) { -						snprintf(fname, 1024, "%s", demangled); -					} - -					if (demangled) { -						free(demangled); -					} -				} -			} - -			String output = fname; - -			// Try to get the file/line number using atos -			if (bt_buffer[i] > (void *)0x0 && OS::get_singleton()) { -				List<String> args; -				char str[1024]; - -				args.push_back("-o"); -				args.push_back(_execpath); -#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) -				args.push_back("-arch"); -				args.push_back("x86_64"); -#elif defined(__aarch64__) -				args.push_back("-arch"); -				args.push_back("arm64"); -#endif -				args.push_back("-l"); -				snprintf(str, 1024, "%p", load_addr); -				args.push_back(str); -				snprintf(str, 1024, "%p", bt_buffer[i]); -				args.push_back(str); - -				int ret; -				String out = ""; -				Error err = OS::get_singleton()->execute(String("atos"), args, &out, &ret); -				if (err == OK && out.substr(0, 2) != "0x") { -					out = out.substr(0, out.length() - 1); -					output = out; -				} -			} - -			print_error(vformat("[%d] %s", (int64_t)i, output)); -		} - -		free(strings); -	} -	print_error("-- END OF BACKTRACE --"); -	print_error("================================================================"); - -	// Abort to pass the error to the OS -	abort(); -} -#endif - -CrashHandler::CrashHandler() { -	disabled = false; -} - -CrashHandler::~CrashHandler() { -	disable(); -} - -void CrashHandler::disable() { -	if (disabled) { -		return; -	} - -#ifdef CRASH_HANDLER_ENABLED -	signal(SIGSEGV, nullptr); -	signal(SIGFPE, nullptr); -	signal(SIGILL, nullptr); -#endif - -	disabled = true; -} - -void CrashHandler::initialize() { -#ifdef CRASH_HANDLER_ENABLED -	signal(SIGSEGV, handle_crash); -	signal(SIGFPE, handle_crash); -	signal(SIGILL, handle_crash); -#endif -} diff --git a/platform/osx/detect.py b/platform/osx/detect.py deleted file mode 100644 index 47765cff71..0000000000 --- a/platform/osx/detect.py +++ /dev/null @@ -1,251 +0,0 @@ -import os -import sys -from methods import detect_darwin_sdk_path - - -def is_active(): -    return True - - -def get_name(): -    return "OSX" - - -def can_build(): -    if sys.platform == "darwin" or ("OSXCROSS_ROOT" in os.environ): -        return True - -    return False - - -def get_opts(): -    from SCons.Variables import BoolVariable, EnumVariable - -    return [ -        ("osxcross_sdk", "OSXCross SDK version", "darwin16"), -        ("MACOS_SDK_PATH", "Path to the macOS 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), -        BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), -        BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False), -        BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False), -        BoolVariable("use_coverage", "Use instrumentation codes in the binary (e.g. for code coverage)", False), -    ] - - -def get_flags(): -    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): -    ## Build type - -    if env["target"] == "release": -        if env["optimize"] == "speed":  # optimize for speed (default) -            env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"]) -        elif env["optimize"] == "size":  # optimize for size -            env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"]) -        if env["arch"] != "arm64": -            env.Prepend(CCFLAGS=["-msse2"]) - -        if env["debug_symbols"]: -            env.Prepend(CCFLAGS=["-g2"]) - -    elif env["target"] == "release_debug": -        if env["optimize"] == "speed":  # optimize for speed (default) -            env.Prepend(CCFLAGS=["-O2"]) -        elif env["optimize"] == "size":  # optimize for size -            env.Prepend(CCFLAGS=["-Os"]) -        if env["debug_symbols"]: -            env.Prepend(CCFLAGS=["-g2"]) - -    elif env["target"] == "debug": -        env.Prepend(CCFLAGS=["-g3"]) -        env.Prepend(LINKFLAGS=["-Xlinker", "-no_deduplicate"]) - -    ## Architecture - -    # Mac OS X no longer runs on 32-bit since 10.7 which is unsupported since 2014 -    # As such, we only support 64-bit -    env["bits"] = "64" - -    ## Compiler configuration - -    # Save this in environment for use by other modules -    if "OSXCROSS_ROOT" in os.environ: -        env["osxcross"] = True - -    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"]) - -    env.Append(CCFLAGS=["-fobjc-arc"]) - -    if not "osxcross" in env:  # regular native build -        if env["macports_clang"] != "no": -            mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") -            mpclangver = env["macports_clang"] -            env["CC"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/clang" -            env["CXX"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/clang++" -            env["AR"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ar" -            env["RANLIB"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib" -            env["AS"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as" -        else: -            env["CC"] = "clang" -            env["CXX"] = "clang++" - -        detect_darwin_sdk_path("osx", env) -        env.Append(CCFLAGS=["-isysroot", "$MACOS_SDK_PATH"]) -        env.Append(LINKFLAGS=["-isysroot", "$MACOS_SDK_PATH"]) - -    else:  # osxcross build -        root = os.environ.get("OSXCROSS_ROOT", 0) -        if env["arch"] == "arm64": -            basecmd = root + "/target/bin/arm64-apple-" + env["osxcross_sdk"] + "-" -        else: -            basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-" - -        ccache_path = os.environ.get("CCACHE") -        if ccache_path is None: -            env["CC"] = basecmd + "cc" -            env["CXX"] = basecmd + "c++" -        else: -            # there aren't any ccache wrappers available for OS X cross-compile, -            # to enable caching we need to prepend the path to the ccache binary -            env["CC"] = ccache_path + " " + basecmd + "cc" -            env["CXX"] = ccache_path + " " + basecmd + "c++" -        env["AR"] = basecmd + "ar" -        env["RANLIB"] = basecmd + "ranlib" -        env["AS"] = basecmd + "as" - -    if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]: -        env.extra_suffix += ".san" -        env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"]) - -        if env["use_ubsan"]: -            env.Append( -                CCFLAGS=[ -                    "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin" -                ] -            ) -            env.Append(LINKFLAGS=["-fsanitize=undefined"]) -            env.Append(CCFLAGS=["-fsanitize=nullability-return,nullability-arg,function,nullability-assign"]) - -        if env["use_asan"]: -            env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"]) -            env.Append(LINKFLAGS=["-fsanitize=address"]) - -        if env["use_tsan"]: -            env.Append(CCFLAGS=["-fsanitize=thread"]) -            env.Append(LINKFLAGS=["-fsanitize=thread"]) - -    if env["use_coverage"]: -        env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"]) -        env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"]) - -    ## Dependencies - -    if env["builtin_libtheora"]: -        if env["arch"] != "arm64": -            env["x86_libtheora_opt_gcc"] = True - -    ## Flags - -    env.Prepend(CPPPATH=["#platform/osx"]) -    env.Append(CPPDEFINES=["OSX_ENABLED", "UNIX_ENABLED", "APPLE_STYLE_KEYS", "COREAUDIO_ENABLED", "COREMIDI_ENABLED"]) -    env.Append( -        LINKFLAGS=[ -            "-framework", -            "Cocoa", -            "-framework", -            "Carbon", -            "-framework", -            "AudioUnit", -            "-framework", -            "CoreAudio", -            "-framework", -            "CoreMIDI", -            "-framework", -            "IOKit", -            "-framework", -            "ForceFeedback", -            "-framework", -            "CoreVideo", -            "-framework", -            "AVFoundation", -            "-framework", -            "CoreMedia", -        ] -    ) -    env.Append(LIBS=["pthread", "z"]) - -    if env["opengl3"]: -        env.Append(CPPDEFINES=["GLES_ENABLED", "GLES3_ENABLED"]) -        env.Append(CCFLAGS=["-Wno-deprecated-declarations"])  # Disable deprecation warnings -        env.Append(LINKFLAGS=["-framework", "OpenGL"]) - -    env.Append(LINKFLAGS=["-rpath", "@executable_path/../Frameworks", "-rpath", "@executable_path"]) - -    if env["vulkan"]: -        env.Append(CPPDEFINES=["VULKAN_ENABLED"]) -        env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "QuartzCore", "-framework", "IOSurface"]) -        if not env["use_volk"]: -            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/osx/dir_access_osx.h deleted file mode 100644 index 3c66c81d4f..0000000000 --- a/platform/osx/dir_access_osx.h +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************/ -/*  dir_access_osx.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 DIR_ACCESS_OSX_H -#define DIR_ACCESS_OSX_H - -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) - -#include <dirent.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "core/io/dir_access.h" -#include "drivers/unix/dir_access_unix.h" - -class DirAccessOSX : public DirAccessUnix { -protected: -	virtual String fix_unicode_name(const char *p_name) const; - -	virtual int get_drive_count(); -	virtual String get_drive(int p_drive); - -	virtual bool is_hidden(const String &p_name); -}; - -#endif //UNIX ENABLED -#endif diff --git a/platform/osx/dir_access_osx.mm b/platform/osx/dir_access_osx.mm deleted file mode 100644 index 6bafb9470d..0000000000 --- a/platform/osx/dir_access_osx.mm +++ /dev/null @@ -1,81 +0,0 @@ -/*************************************************************************/ -/*  dir_access_osx.mm                                                    */ -/*************************************************************************/ -/*                       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 "dir_access_osx.h" - -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) - -#include <errno.h> - -#import <AppKit/NSWorkspace.h> -#import <Foundation/Foundation.h> - -String DirAccessOSX::fix_unicode_name(const char *p_name) const { -	String fname; -	NSString *nsstr = [[NSString stringWithUTF8String:p_name] precomposedStringWithCanonicalMapping]; - -	fname.parse_utf8([nsstr UTF8String]); - -	return fname; -} - -int DirAccessOSX::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) { -	NSArray *res_keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsSystemImmutableKey, nil]; -	NSArray *vols = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:res_keys options:NSVolumeEnumerationSkipHiddenVolumes]; -	int count = [vols count]; - -	ERR_FAIL_INDEX_V(p_drive, count, ""); - -	String volname; -	NSString *path = [vols[p_drive] path]; - -	volname.parse_utf8([path UTF8String]); - -	return volname; -} - -bool DirAccessOSX::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; -	if (![url getResourceValue:&hidden forKey:NSURLIsHiddenKey error:nil]) { -		return DirAccessUnix::is_hidden(p_name); -	} -	return [hidden boolValue]; -} - -#endif //posix_enabled diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h deleted file mode 100644 index 9575cb29a2..0000000000 --- a/platform/osx/display_server_osx.h +++ /dev/null @@ -1,406 +0,0 @@ -/*************************************************************************/ -/*  display_server_osx.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 DISPLAY_SERVER_OSX_H -#define DISPLAY_SERVER_OSX_H - -#define BitMap _QDBitMap // Suppress deprecated QuickDraw definition. - -#include "core/input/input.h" -#include "servers/display_server.h" - -#if defined(GLES3_ENABLED) -#include "gl_manager_osx_legacy.h" -#endif // GLES3_ENABLED - -#if defined(VULKAN_ENABLED) -#include "drivers/vulkan/rendering_device_vulkan.h" -#include "platform/osx/vulkan_context_osx.h" -#endif // VULKAN_ENABLED - -#import <AppKit/AppKit.h> -#import <AppKit/NSCursor.h> -#import <ApplicationServices/ApplicationServices.h> -#import <CoreVideo/CoreVideo.h> -#import <Foundation/Foundation.h> - -#undef BitMap -#undef CursorShape - -class DisplayServerOSX : public DisplayServer { -	GDCLASS(DisplayServerOSX, DisplayServer) - -	_THREAD_SAFE_CLASS_ - -public: -	struct KeyEvent { -		WindowID window_id = INVALID_WINDOW_ID; -		unsigned int osx_state = false; -		bool pressed = false; -		bool echo = false; -		bool raw = false; -		Key keycode = Key::NONE; -		Key physical_keycode = Key::NONE; -		uint32_t unicode = 0; -	}; - -	struct WindowData { -		id window_delegate; -		id window_object; -		id window_view; - -		Vector<Vector2> mpath; - -		Point2i mouse_pos; - -		Size2i min_size; -		Size2i max_size; -		Size2i size; - -		bool im_active = false; -		Size2i im_position; - -		Callable rect_changed_callback; -		Callable event_callback; -		Callable input_event_callback; -		Callable input_text_callback; -		Callable drop_files_callback; - -		ObjectID instance_id; - -		WindowID transient_parent = INVALID_WINDOW_ID; -		bool exclusive = false; -		HashSet<WindowID> transient_children; - -		bool layered_window = false; -		bool fullscreen = false; -		bool on_top = false; -		bool borderless = false; -		bool resize_disabled = false; -		bool no_focus = false; -		bool is_popup = false; - -		Rect2i parent_safe_rect; -	}; - -	List<WindowID> popup_list; -	uint64_t time_since_popup = 0; - -private: -#if defined(GLES3_ENABLED) -	GLManager_OSX *gl_manager = nullptr; -#endif -#if defined(VULKAN_ENABLED) -	VulkanContextOSX *context_vulkan = nullptr; -	RenderingDeviceVulkan *rendering_device_vulkan = nullptr; -#endif -	String rendering_driver; - -	NSMenu *apple_menu = nullptr; -	NSMenu *dock_menu = nullptr; -	HashMap<String, NSMenu *> submenu; - -	struct WarpEvent { -		NSTimeInterval timestamp; -		NSPoint delta; -	}; -	List<WarpEvent> warp_events; -	NSTimeInterval last_warp = 0; -	bool ignore_warp = false; - -	Vector<KeyEvent> key_event_buffer; -	int key_event_pos = 0; - -	id tts = nullptr; - -	Point2i im_selection; -	String im_text; - -	CGEventSourceRef event_source; -	MouseMode mouse_mode = MOUSE_MODE_VISIBLE; -	MouseButton last_button_state = MouseButton::NONE; - -	bool drop_events = false; -	bool in_dispatch_input_event = false; - -	struct LayoutInfo { -		String name; -		String code; -	}; -	Vector<LayoutInfo> kbd_layouts; -	int current_layout = 0; -	bool keyboard_layout_dirty = true; - -	WindowID last_focused_window = INVALID_WINDOW_ID; -	WindowID window_id_counter = MAIN_WINDOW_ID; -	float display_max_scale = 1.f; -	Point2i origin; -	bool displays_arrangement_dirty = true; -	bool is_resizing = false; - -	CursorShape cursor_shape = CURSOR_ARROW; -	NSCursor *cursors[CURSOR_MAX]; -	HashMap<CursorShape, Vector<Variant>> cursors_cache; - -	HashMap<WindowID, WindowData> windows; - -	const NSMenu *_get_menu_root(const String &p_menu_root) const; -	NSMenu *_get_menu_root(const String &p_menu_root); - -	WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect); -	void _update_window_style(WindowData p_wd); -	void _set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window); - -	void _update_displays_arrangement(); -	Point2i _get_screens_origin() const; -	Point2i _get_native_screen_position(int p_screen) const; -	static void _displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info); - -	static void _dispatch_input_events(const Ref<InputEvent> &p_event); -	void _dispatch_input_event(const Ref<InputEvent> &p_event); -	void _push_input(const Ref<InputEvent> &p_event); -	void _process_key_events(); -	void _update_keyboard_layouts(); -	static void _keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info); -	NSImage *_convert_to_nsimg(Ref<Image> &p_image) const; - -	static NSCursor *_cursor_from_selector(SEL p_selector, SEL p_fallback = nil); - -public: -	NSMenu *get_dock_menu() const; -	void menu_callback(id p_sender); - -	bool has_window(WindowID p_window) const; -	WindowData &get_window(WindowID p_window); - -	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 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); -	void set_last_focused_window(WindowID p_window); -	bool mouse_process_popups(bool p_close = false); -	void popup_open(WindowID p_window); -	void popup_close(WindowID p_window); -	void set_is_resizing(bool p_is_resizing); -	bool get_is_resizing() const; - -	void window_update(WindowID p_window); -	void window_destroy(WindowID p_window); -	void window_resize(WindowID p_window, int p_width, int p_height); - -	virtual bool has_feature(Feature p_feature) const override; -	virtual String get_name() const override; - -	virtual void global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; -	virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; -	virtual void global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; -	virtual void global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; -	virtual void global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; -	virtual void 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 = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; -	virtual void 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 = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; -	virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1) override; -	virtual void global_menu_add_separator(const String &p_menu_root, int p_index = -1) override; - -	virtual int global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const override; -	virtual int global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const override; - -	virtual bool global_menu_is_item_checked(const String &p_menu_root, int p_idx) const override; -	virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const override; -	virtual bool global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const override; -	virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx) const override; -	virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx) const override; -	virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx) const override; -	virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const override; -	virtual Key global_menu_get_item_accelerator(const String &p_menu_root, int p_idx) const override; -	virtual bool global_menu_is_item_disabled(const String &p_menu_root, int p_idx) const override; -	virtual String global_menu_get_item_tooltip(const String &p_menu_root, int p_idx) const override; -	virtual int global_menu_get_item_state(const String &p_menu_root, int p_idx) const override; -	virtual int global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const override; -	virtual Ref<Texture2D> global_menu_get_item_icon(const String &p_menu_root, int p_idx) const override; - -	virtual void global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) override; -	virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override; -	virtual void global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override; -	virtual void global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) override; -	virtual void global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) override; -	virtual void global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) override; -	virtual void global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) override; -	virtual void global_menu_set_item_accelerator(const String &p_menu_root, int p_idx, Key p_keycode) override; -	virtual void global_menu_set_item_disabled(const String &p_menu_root, int p_idx, bool p_disabled) override; -	virtual void global_menu_set_item_tooltip(const String &p_menu_root, int p_idx, const String &p_tooltip) override; -	virtual void global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) override; -	virtual void global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) override; -	virtual void global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) override; - -	virtual int global_menu_get_item_count(const String &p_menu_root) const override; - -	virtual void global_menu_remove_item(const String &p_menu_root, int p_idx) override; -	virtual void global_menu_clear(const String &p_menu_root) override; - -	virtual bool tts_is_speaking() const override; -	virtual bool tts_is_paused() const override; -	virtual Array tts_get_voices() const override; - -	virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; -	virtual void tts_pause() override; -	virtual void tts_resume() override; -	virtual void tts_stop() override; - -	virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) override; -	virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override; - -	virtual void mouse_set_mode(MouseMode p_mode) override; -	virtual MouseMode mouse_get_mode() const override; - -	bool update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSPoint &r_mpos, NSTimeInterval p_timestamp); -	virtual void warp_mouse(const Point2i &p_position) override; -	virtual Point2i mouse_get_position() const override; -	void mouse_set_button_state(MouseButton p_state); -	virtual MouseButton mouse_get_button_state() const override; - -	virtual void clipboard_set(const String &p_text) override; -	virtual String clipboard_get() const override; - -	virtual int get_screen_count() const override; -	virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; -	virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; -	virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; -	virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; -	virtual float screen_get_max_scale() const override; -	virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; -	virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; - -	virtual Vector<int> get_window_list() const override; - -	virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; -	virtual void show_window(WindowID p_id) override; -	virtual void delete_sub_window(WindowID p_id) override; - -	virtual WindowID window_get_active_popup() const override; -	virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) override; -	virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const override; - -	virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; - -	virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override; - -	virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override; -	virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override; - -	virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override; -	virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override; - -	virtual void window_set_transient(WindowID p_window, WindowID p_parent) override; -	virtual void window_set_exclusive(WindowID p_window, bool p_exclusive) override; - -	virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override; - -	virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override; - -	virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override; -	virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const override; - -	virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override; - -	virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override; - -	virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override; - -	virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; -	virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; - -	virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; - -	virtual bool can_any_window_draw() const override; - -	virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID) override; - -	virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override; - -	virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override; - -	virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override; -	virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override; - -	virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; -	virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; - -	virtual Point2i ime_get_selection() const override; -	virtual String ime_get_text() const override; - -	void cursor_update_shape(); -	virtual void cursor_set_shape(CursorShape p_shape) override; -	virtual CursorShape cursor_get_shape() const override; -	virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; - -	virtual bool get_swap_cancel_ok() override; - -	virtual int keyboard_get_layout_count() const override; -	virtual int keyboard_get_current_layout() const override; -	virtual void keyboard_set_current_layout(int p_index) override; -	virtual String keyboard_get_layout_language(int p_index) const override; -	virtual String keyboard_get_layout_name(int p_index) const override; -	virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; - -	virtual void process_events() override; -	virtual void force_process_and_drop_events() override; - -	virtual void release_rendering_thread() override; -	virtual void make_rendering_thread() override; -	virtual void swap_buffers() override; - -	virtual void set_native_icon(const String &p_filename) override; -	virtual void set_icon(const Ref<Image> &p_icon) override; - -	static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); -	static Vector<String> get_rendering_drivers_func(); - -	static void register_osx_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(); -}; - -#endif // DISPLAY_SERVER_OSX_H diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm deleted file mode 100644 index 11474dac46..0000000000 --- a/platform/osx/display_server_osx.mm +++ /dev/null @@ -1,3304 +0,0 @@ -/*************************************************************************/ -/*  display_server_osx.mm                                                */ -/*************************************************************************/ -/*                       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 "display_server_osx.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 "tts_osx.h" - -#include "core/io/marshalls.h" -#include "core/math/geometry_2d.h" -#include "core/os/keyboard.h" -#include "main/main.h" -#include "scene/resources/texture.h" - -#import <Carbon/Carbon.h> -#import <Cocoa/Cocoa.h> -#import <IOKit/IOCFPlugIn.h> -#import <IOKit/IOKitLib.h> -#import <IOKit/hid/IOHIDKeys.h> -#import <IOKit/hid/IOHIDLib.h> - -#if defined(GLES3_ENABLED) -#include "drivers/gles3/rasterizer_gles3.h" -#endif - -#if defined(VULKAN_ENABLED) -#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" -#endif - -const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const { -	const NSMenu *menu = nullptr; -	if (p_menu_root == "") { -		// Main menu. -		menu = [NSApp mainMenu]; -	} else if (p_menu_root.to_lower() == "_dock") { -		// macOS dock menu. -		menu = dock_menu; -	} else { -		// Submenu. -		if (submenu.has(p_menu_root)) { -			menu = submenu[p_menu_root]; -		} -	} -	if (menu == apple_menu) { -		// Do not allow to change Apple menu. -		return nullptr; -	} -	return menu; -} - -NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) { -	NSMenu *menu = nullptr; -	if (p_menu_root == "") { -		// Main menu. -		menu = [NSApp mainMenu]; -	} else if (p_menu_root.to_lower() == "_dock") { -		// macOS dock menu. -		menu = dock_menu; -	} else { -		// Submenu. -		if (!submenu.has(p_menu_root)) { -			NSMenu *n_menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:p_menu_root.utf8().get_data()]]; -			[n_menu setAutoenablesItems:NO]; -			submenu[p_menu_root] = n_menu; -		} -		menu = submenu[p_menu_root]; -	} -	if (menu == apple_menu) { -		// Do not allow to change Apple menu. -		return nullptr; -	} -	return menu; -} - -DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) { -	WindowID id; -	const float scale = screen_get_max_scale(); -	{ -		WindowData wd; - -		wd.window_delegate = [[GodotWindowDelegate alloc] init]; -		ERR_FAIL_COND_V_MSG(wd.window_delegate == nil, INVALID_WINDOW_ID, "Can't create a window delegate"); -		[wd.window_delegate setWindowID:window_id_counter]; - -		Point2i position = p_rect.position; -		// OS X native y-coordinate relative to _get_screens_origin() is negative, -		// Godot passes a positive value. -		position.y *= -1; -		position += _get_screens_origin(); - -		// initWithContentRect uses bottom-left corner of the window’s frame as origin. -		wd.window_object = [[GodotWindow alloc] -				initWithContentRect:NSMakeRect(position.x / scale, (position.y - p_rect.size.height) / scale, p_rect.size.width / scale, p_rect.size.height / scale) -						  styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable -							backing:NSBackingStoreBuffered -							  defer:NO]; -		ERR_FAIL_COND_V_MSG(wd.window_object == nil, INVALID_WINDOW_ID, "Can't create a window"); -		[wd.window_object setWindowID:window_id_counter]; - -		wd.window_view = [[GodotContentView alloc] init]; -		ERR_FAIL_COND_V_MSG(wd.window_view == nil, INVALID_WINDOW_ID, "Can't create a window view"); -		[wd.window_view setWindowID:window_id_counter]; -		[wd.window_view setWantsLayer:TRUE]; - -		[wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; -		[wd.window_object setContentView:wd.window_view]; -		[wd.window_object setDelegate:wd.window_delegate]; -		[wd.window_object setAcceptsMouseMovedEvents:YES]; -		[wd.window_object setRestorable:NO]; -		[wd.window_object setColorSpace:[NSColorSpace sRGBColorSpace]]; - -		if ([wd.window_object respondsToSelector:@selector(setTabbingMode:)]) { -			[wd.window_object setTabbingMode:NSWindowTabbingModeDisallowed]; -		} - -		CALayer *layer = [(NSView *)wd.window_view layer]; -		if (layer) { -			layer.contentsScale = scale; -		} - -#if defined(VULKAN_ENABLED) -		if (context_vulkan) { -			Error err = context_vulkan->window_create(window_id_counter, p_vsync_mode, wd.window_view, p_rect.size.width, p_rect.size.height); -			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan context"); -		} -#endif -#if defined(GLES3_ENABLED) -		if (gl_manager) { -			Error err = gl_manager->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height); -			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context"); -		} -#endif -		id = window_id_counter++; -		windows[id] = wd; -	} - -	WindowData &wd = windows[id]; -	window_set_mode(p_mode, id); - -	const NSRect contentRect = [wd.window_view frame]; -	wd.size.width = contentRect.size.width * scale; -	wd.size.height = contentRect.size.height * scale; - -	CALayer *layer = [(NSView *)wd.window_view layer]; -	if (layer) { -		layer.contentsScale = scale; -	} - -#if defined(GLES3_ENABLED) -	if (gl_manager) { -		gl_manager->window_resize(id, wd.size.width, wd.size.height); -	} -#endif -#if defined(VULKAN_ENABLED) -	if (context_vulkan) { -		context_vulkan->window_resize(id, wd.size.width, wd.size.height); -	} -#endif - -	return id; -} - -void DisplayServerOSX::_update_window_style(WindowData p_wd) { -	bool borderless_full = false; - -	if (p_wd.borderless) { -		NSRect frameRect = [p_wd.window_object frame]; -		NSRect screenRect = [[p_wd.window_object screen] frame]; - -		// Check if our window covers up the screen. -		if (frameRect.origin.x <= screenRect.origin.x && frameRect.origin.y <= frameRect.origin.y && -				frameRect.size.width >= screenRect.size.width && frameRect.size.height >= screenRect.size.height) { -			borderless_full = true; -		} -	} - -	if (borderless_full) { -		// If the window covers up the screen set the level to above the main menu and hide on deactivate. -		[(NSWindow *)p_wd.window_object setLevel:NSMainMenuWindowLevel + 1]; -		[(NSWindow *)p_wd.window_object setHidesOnDeactivate:YES]; -	} else { -		// Reset these when our window is not a borderless window that covers up the screen. -		if (p_wd.on_top && !p_wd.fullscreen) { -			[(NSWindow *)p_wd.window_object setLevel:NSFloatingWindowLevel]; -		} else { -			[(NSWindow *)p_wd.window_object setLevel:NSNormalWindowLevel]; -		} -		[(NSWindow *)p_wd.window_object setHidesOnDeactivate:NO]; -	} -} - -void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window) { -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	if (!OS::get_singleton()->is_layered_allowed()) { -		return; -	} -	if (wd.layered_window != p_enabled) { -		if (p_enabled) { -			[wd.window_object setBackgroundColor:[NSColor clearColor]]; -			[wd.window_object setOpaque:NO]; -			[wd.window_object setHasShadow:NO]; -			CALayer *layer = [(NSView *)wd.window_view layer]; -			if (layer) { -				[layer setBackgroundColor:[NSColor clearColor].CGColor]; -				[layer setOpaque:NO]; -			} -#if defined(GLES3_ENABLED) -			if (gl_manager) { -				gl_manager->window_set_per_pixel_transparency_enabled(p_window, true); -			} -#endif -			wd.layered_window = true; -		} else { -			[wd.window_object setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1]]; -			[wd.window_object setOpaque:YES]; -			[wd.window_object setHasShadow:YES]; -			CALayer *layer = [(NSView *)wd.window_view layer]; -			if (layer) { -				[layer setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1].CGColor]; -				[layer setOpaque:YES]; -			} -#if defined(GLES3_ENABLED) -			if (gl_manager) { -				gl_manager->window_set_per_pixel_transparency_enabled(p_window, false); -			} -#endif -			wd.layered_window = false; -		} -		NSRect frameRect = [wd.window_object frame]; -		[wd.window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:YES]; -		[wd.window_object setFrame:frameRect display:YES]; -	} -} - -void DisplayServerOSX::_update_displays_arrangement() { -	origin = Point2i(); - -	for (int i = 0; i < get_screen_count(); i++) { -		Point2i position = _get_native_screen_position(i); -		if (position.x < origin.x) { -			origin.x = position.x; -		} -		if (position.y > origin.y) { -			origin.y = position.y; -		} -	} -	displays_arrangement_dirty = false; -} - -Point2i DisplayServerOSX::_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(); -	} - -	return origin; -} - -Point2i DisplayServerOSX::_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]; -		// Return the top-left corner of the screen, for OS X the y starts at the bottom. -		return Point2i(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * screen_get_max_scale(); -	} - -	return Point2i(); -} - -void DisplayServerOSX::_displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) { -	DisplayServerOSX *ds = (DisplayServerOSX *)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 DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { -	_THREAD_SAFE_METHOD_ -	if (!in_dispatch_input_event) { -		in_dispatch_input_event = true; - -		Variant ev = p_event; -		Variant *evp = &ev; -		Variant ret; -		Callable::CallError ce; - -		{ -			List<WindowID>::Element *E = popup_list.back(); -			if (E && Object::cast_to<InputEventKey>(*p_event)) { -				// Redirect keyboard input to active popup. -				if (windows.has(E->get())) { -					Callable callable = windows[E->get()].input_event_callback; -					if (callable.is_valid()) { -						callable.call((const Variant **)&evp, 1, ret, ce); -					} -				} -				in_dispatch_input_event = false; -				return; -			} -		} - -		Ref<InputEventFromWindow> event_from_window = p_event; -		if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) { -			// Send to a window. -			if (windows.has(event_from_window->get_window_id())) { -				Callable callable = windows[event_from_window->get_window_id()].input_event_callback; -				if (callable.is_valid()) { -					callable.call((const Variant **)&evp, 1, ret, ce); -				} -			} -		} else { -			// Send to all windows. -			for (KeyValue<WindowID, WindowData> &E : windows) { -				Callable callable = E.value.input_event_callback; -				if (callable.is_valid()) { -					callable.call((const Variant **)&evp, 1, ret, ce); -				} -			} -		} -		in_dispatch_input_event = false; -	} -} - -void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) { -	Ref<InputEvent> ev = p_event; -	Input::get_singleton()->parse_input_event(ev); -} - -void DisplayServerOSX::_process_key_events() { -	Ref<InputEventKey> k; -	for (int i = 0; i < key_event_pos; i++) { -		const KeyEvent &ke = key_event_buffer[i]; -		if (ke.raw) { -			// Non IME input - no composite characters, pass events as is. -			k.instantiate(); - -			k->set_window_id(ke.window_id); -			get_key_modifier_state(ke.osx_state, k); -			k->set_pressed(ke.pressed); -			k->set_echo(ke.echo); -			k->set_keycode(ke.keycode); -			k->set_physical_keycode((Key)ke.physical_keycode); -			k->set_unicode(ke.unicode); - -			_push_input(k); -		} else { -			// IME input. -			if ((i == 0 && ke.keycode == Key::NONE) || (i > 0 && key_event_buffer[i - 1].keycode == Key::NONE)) { -				k.instantiate(); - -				k->set_window_id(ke.window_id); -				get_key_modifier_state(ke.osx_state, k); -				k->set_pressed(ke.pressed); -				k->set_echo(ke.echo); -				k->set_keycode(Key::NONE); -				k->set_physical_keycode(Key::NONE); -				k->set_unicode(ke.unicode); - -				_push_input(k); -			} -			if (ke.keycode != Key::NONE) { -				k.instantiate(); - -				k->set_window_id(ke.window_id); -				get_key_modifier_state(ke.osx_state, k); -				k->set_pressed(ke.pressed); -				k->set_echo(ke.echo); -				k->set_keycode(ke.keycode); -				k->set_physical_keycode((Key)ke.physical_keycode); - -				if (i + 1 < key_event_pos && key_event_buffer[i + 1].keycode == Key::NONE) { -					k->set_unicode(key_event_buffer[i + 1].unicode); -				} - -				_push_input(k); -			} -		} -	} - -	key_event_pos = 0; -} - -void DisplayServerOSX::_update_keyboard_layouts() { -	kbd_layouts.clear(); -	current_layout = 0; - -	TISInputSourceRef cur_source = TISCopyCurrentKeyboardInputSource(); -	NSString *cur_name = (__bridge NSString *)TISGetInputSourceProperty(cur_source, kTISPropertyLocalizedName); -	CFRelease(cur_source); - -	// Enum IME layouts. -	NSDictionary *filter_ime = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardInputMode }; -	NSArray *list_ime = (__bridge NSArray *)TISCreateInputSourceList((__bridge CFDictionaryRef)filter_ime, false); -	for (NSUInteger i = 0; i < [list_ime count]; i++) { -		LayoutInfo ly; -		NSString *name = (__bridge NSString *)TISGetInputSourceProperty((__bridge TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyLocalizedName); -		ly.name.parse_utf8([name UTF8String]); - -		NSArray *langs = (__bridge NSArray *)TISGetInputSourceProperty((__bridge TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyInputSourceLanguages); -		ly.code.parse_utf8([(NSString *)[langs objectAtIndex:0] UTF8String]); -		kbd_layouts.push_back(ly); - -		if ([name isEqualToString:cur_name]) { -			current_layout = kbd_layouts.size() - 1; -		} -	} - -	// Enum plain keyboard layouts. -	NSDictionary *filter_kbd = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardLayout }; -	NSArray *list_kbd = (__bridge NSArray *)TISCreateInputSourceList((__bridge CFDictionaryRef)filter_kbd, false); -	for (NSUInteger i = 0; i < [list_kbd count]; i++) { -		LayoutInfo ly; -		NSString *name = (__bridge NSString *)TISGetInputSourceProperty((__bridge TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyLocalizedName); -		ly.name.parse_utf8([name UTF8String]); - -		NSArray *langs = (__bridge NSArray *)TISGetInputSourceProperty((__bridge TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyInputSourceLanguages); -		ly.code.parse_utf8([(NSString *)[langs objectAtIndex:0] UTF8String]); -		kbd_layouts.push_back(ly); - -		if ([name isEqualToString:cur_name]) { -			current_layout = kbd_layouts.size() - 1; -		} -	} - -	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(); -	if (ds) { -		ds->keyboard_layout_dirty = true; -	} -} - -NSImage *DisplayServerOSX::_convert_to_nsimg(Ref<Image> &p_image) const { -	p_image->convert(Image::FORMAT_RGBA8); -	NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] -			initWithBitmapDataPlanes:NULL -						  pixelsWide:p_image->get_width() -						  pixelsHigh:p_image->get_height() -					   bitsPerSample:8 -					 samplesPerPixel:4 -							hasAlpha:YES -							isPlanar:NO -					  colorSpaceName:NSDeviceRGBColorSpace -						 bytesPerRow:int(p_image->get_width()) * 4 -						bitsPerPixel:32]; -	ERR_FAIL_COND_V(imgrep == nil, nil); -	uint8_t *pixels = [imgrep bitmapData]; - -	int len = p_image->get_width() * p_image->get_height(); -	const uint8_t *r = p_image->get_data().ptr(); - -	/* Premultiply the alpha channel */ -	for (int i = 0; i < len; i++) { -		uint8_t alpha = r[i * 4 + 3]; -		pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255); -		pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255); -		pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255); -		pixels[i * 4 + 3] = alpha; -	} - -	NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(p_image->get_width(), p_image->get_height())]; -	ERR_FAIL_COND_V(nsimg == nil, nil); -	[nsimg addRepresentation:imgrep]; -	return nsimg; -} - -NSCursor *DisplayServerOSX::_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]]) { -			return object; -		} -	} -	if (p_fallback) { -		// Fallback should be a reasonable default, no need to check. -		return [NSCursor performSelector:p_fallback]; -	} -	return [NSCursor arrowCursor]; -} - -NSMenu *DisplayServerOSX::get_dock_menu() const { -	return dock_menu; -} - -void DisplayServerOSX::menu_callback(id p_sender) { -	if (![p_sender representedObject]) { -		return; -	} - -	GodotMenuItem *value = [p_sender representedObject]; - -	if (value) { -		if (value->max_states > 0) { -			value->state++; -			if (value->state >= value->max_states) { -				value->state = 0; -			} -		} - -		if (value->checkable_type == CHECKABLE_TYPE_CHECK_BOX) { -			if ([p_sender state] == NSControlStateValueOff) { -				[p_sender setState:NSControlStateValueOn]; -			} else { -				[p_sender setState:NSControlStateValueOff]; -			} -		} - -		if (value->callback != Callable()) { -			Variant tag = value->meta; -			Variant *tagp = &tag; -			Variant ret; -			Callable::CallError ce; -			value->callback.call((const Variant **)&tagp, 1, ret, ce); -		} -	} -} - -bool DisplayServerOSX::has_window(WindowID p_window) const { -	return windows.has(p_window); -} - -DisplayServerOSX::WindowData &DisplayServerOSX::get_window(WindowID p_window) { -	return windows[p_window]; -} - -void DisplayServerOSX::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) { -		if (([p_event modifierFlags] & NSEventModifierFlagCommand) && [p_event keyCode] == 0x2f) { -			Ref<InputEventKey> k; -			k.instantiate(); - -			get_key_modifier_state([p_event modifierFlags], k); -			k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID); -			k->set_pressed(true); -			k->set_keycode(Key::PERIOD); -			k->set_physical_keycode(Key::PERIOD); -			k->set_echo([p_event isARepeat]); - -			Input::get_singleton()->parse_input_event(k); -		} -	} -} - -void DisplayServerOSX::send_window_event(const WindowData &wd, WindowEvent p_event) { -	_THREAD_SAFE_METHOD_ - -	if (!wd.event_callback.is_null()) { -		Variant event = int(p_event); -		Variant *eventp = &event; -		Variant ret; -		Callable::CallError ce; -		wd.event_callback.call((const Variant **)&eventp, 1, ret, ce); -	} -} - -void DisplayServerOSX::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 DisplayServerOSX::update_mouse_pos(DisplayServerOSX::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; -	p_wd.mouse_pos.y = (content_rect.size.height - p_location_in_window.y) * scale; -	Input::get_singleton()->set_mouse_position(p_wd.mouse_pos); -} - -void DisplayServerOSX::push_to_key_event_buffer(const DisplayServerOSX::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) { -	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) { -	last_focused_window = p_window; -} - -void DisplayServerOSX::set_is_resizing(bool p_is_resizing) { -	is_resizing = p_is_resizing; -} - -bool DisplayServerOSX::get_is_resizing() const { -	return is_resizing; -} - -void DisplayServerOSX::window_update(WindowID p_window) { -#if defined(GLES3_ENABLED) -	if (gl_manager) { -		gl_manager->window_update(p_window); -	} -#endif -} - -void DisplayServerOSX::window_destroy(WindowID p_window) { -#if defined(GLES3_ENABLED) -	if (gl_manager) { -		gl_manager->window_destroy(p_window); -	} -#endif -#ifdef VULKAN_ENABLED -	if (context_vulkan) { -		context_vulkan->window_destroy(p_window); -	} -#endif -	windows.erase(p_window); -} - -void DisplayServerOSX::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); -	} -#endif -#if defined(VULKAN_ENABLED) -	if (context_vulkan) { -		context_vulkan->window_resize(p_window, p_width, p_height); -	} -#endif -} - -bool DisplayServerOSX::has_feature(Feature p_feature) const { -	switch (p_feature) { -		case FEATURE_GLOBAL_MENU: -		case FEATURE_SUBWINDOWS: -		//case FEATURE_TOUCHSCREEN: -		case FEATURE_MOUSE: -		case FEATURE_MOUSE_WARP: -		case FEATURE_CLIPBOARD: -		case FEATURE_CURSOR_SHAPE: -		case FEATURE_CUSTOM_CURSOR_SHAPE: -		case FEATURE_NATIVE_DIALOG: -		case FEATURE_IME: -		case FEATURE_WINDOW_TRANSPARENCY: -		case FEATURE_HIDPI: -		case FEATURE_ICON: -		case FEATURE_NATIVE_ICON: -		//case FEATURE_KEEP_SCREEN_ON: -		case FEATURE_SWAP_BUFFERS: -		case FEATURE_TEXT_TO_SPEECH: -			return true; -		default: { -		} -	} -	return false; -} - -String DisplayServerOSX::get_name() const { -	return "OSX"; -} - -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) { -	_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); -		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]; -		} else { -			menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; -		} -		GodotMenuItem *obj = [[GodotMenuItem alloc] init]; -		obj->callback = p_callback; -		obj->meta = p_tag; -		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 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) { -	_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); -		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]; -		} else { -			menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; -		} -		GodotMenuItem *obj = [[GodotMenuItem alloc] init]; -		obj->callback = p_callback; -		obj->meta = p_tag; -		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 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) { -	_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); -		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]; -		} else { -			menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; -		} -		GodotMenuItem *obj = [[GodotMenuItem alloc] init]; -		obj->callback = p_callback; -		obj->meta = p_tag; -		obj->checkable_type = CHECKABLE_TYPE_NONE; -		obj->max_states = 0; -		obj->state = 0; -		if (p_icon.is_valid()) { -			obj->img = p_icon->get_image(); -			obj->img = obj->img->duplicate(); -			if (obj->img->is_compressed()) { -				obj->img->decompress(); -			} -			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 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) { -	_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); -		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]; -		} else { -			menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; -		} -		GodotMenuItem *obj = [[GodotMenuItem alloc] init]; -		obj->callback = p_callback; -		obj->meta = p_tag; -		obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX; -		obj->max_states = 0; -		obj->state = 0; -		if (p_icon.is_valid()) { -			obj->img = p_icon->get_image(); -			obj->img = obj->img->duplicate(); -			if (obj->img->is_compressed()) { -				obj->img->decompress(); -			} -			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 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) { -	_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); -		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]; -		} else { -			menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; -		} -		GodotMenuItem *obj = [[GodotMenuItem alloc] init]; -		obj->callback = p_callback; -		obj->meta = p_tag; -		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 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) { -	_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); -		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]; -		} else { -			menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; -		} -		GodotMenuItem *obj = [[GodotMenuItem alloc] init]; -		obj->callback = p_callback; -		obj->meta = p_tag; -		obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON; -		obj->max_states = 0; -		obj->state = 0; -		if (p_icon.is_valid()) { -			obj->img = p_icon->get_image(); -			obj->img = obj->img->duplicate(); -			if (obj->img->is_compressed()) { -				obj->img->decompress(); -			} -			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 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) { -	_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); -		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]; -		} else { -			menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; -		} -		GodotMenuItem *obj = [[GodotMenuItem alloc] init]; -		obj->callback = p_callback; -		obj->meta = p_tag; -		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 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) { -	_THREAD_SAFE_METHOD_ - -	NSMenu *menu = _get_menu_root(p_menu_root); -	NSMenu *sub_menu = _get_menu_root(p_submenu); -	if (menu && sub_menu) { -		if (sub_menu == menu) { -			ERR_PRINT("Can't set submenu to self!"); -			return; -		} -		if ([sub_menu supermenu]) { -			ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!"); -			return; -		} -		NSMenuItem *menu_item; -		if (p_index != -1) { -			menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index]; -		} else { -			menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@""]; -		} -		[sub_menu setTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()]]; -		[menu setSubmenu:sub_menu forItem:menu_item]; -	} -} - -void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root, int p_index) { -	_THREAD_SAFE_METHOD_ - -	NSMenu *menu = _get_menu_root(p_menu_root); -	if (menu) { -		if (p_index != -1) { -			[menu insertItem:[NSMenuItem separatorItem] atIndex:p_index]; -		} else { -			[menu addItem:[NSMenuItem separatorItem]]; -		} -	} -} - -int DisplayServerOSX::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); -	if (menu) { -		return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]]; -	} - -	return -1; -} - -int DisplayServerOSX::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); -	if (menu) { -		for (NSInteger i = 0; i < [menu numberOfItems]; i++) { -			const NSMenuItem *menu_item = [menu itemAtIndex:i]; -			if (menu_item) { -				const GodotMenuItem *obj = [menu_item representedObject]; -				if (obj && obj->meta == p_tag) { -					return i; -				} -			} -		} -	} - -	return -1; -} - -bool DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			return ([menu_item state] == NSControlStateValueOn); -		} -	} -	return false; -} - -bool DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				return obj->checkable_type == CHECKABLE_TYPE_CHECK_BOX; -			} -		} -	} -	return false; -} - -bool DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				return obj->checkable_type == CHECKABLE_TYPE_RADIO_BUTTON; -			} -		} -	} -	return false; -} - -Callable DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				return obj->callback; -			} -		} -	} -	return Callable(); -} - -Variant DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				return obj->meta; -			} -		} -	} -	return Variant(); -} - -String DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			return String::utf8([[menu_item title] UTF8String]); -		} -	} -	return String(); -} - -String DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			const NSMenu *sub_menu = [menu_item submenu]; -			if (sub_menu) { -				for (const KeyValue<String, NSMenu *> &E : submenu) { -					if (E.value == sub_menu) { -						return E.key; -					} -				} -			} -		} -	} -	return String(); -} - -Key DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			String ret = String::utf8([[menu_item keyEquivalent] UTF8String]); -			Key keycode = find_keycode(ret); -			NSUInteger mask = [menu_item keyEquivalentModifierMask]; -			if (mask & NSEventModifierFlagControl) { -				keycode |= KeyModifierMask::CTRL; -			} -			if (mask & NSEventModifierFlagOption) { -				keycode |= KeyModifierMask::ALT; -			} -			if (mask & NSEventModifierFlagShift) { -				keycode |= KeyModifierMask::SHIFT; -			} -			if (mask & NSEventModifierFlagCommand) { -				keycode |= KeyModifierMask::META; -			} -			if (mask & NSEventModifierFlagNumericPad) { -				keycode |= KeyModifierMask::KPAD; -			} -			return keycode; -		} -	} -	return Key::NONE; -} - -bool DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			return ![menu_item isEnabled]; -		} -	} -	return false; -} - -String DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			return String::utf8([[menu_item toolTip] UTF8String]); -		} -	} -	return String(); -} - -int DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				return obj->state; -			} -		} -	} -	return 0; -} - -int DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				return obj->max_states; -			} -		} -	} -	return 0; -} - -Ref<Texture2D> DisplayServerOSX::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); -	if (menu) { -		const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				if (obj->img.is_valid()) { -					return ImageTexture::create_from_image(obj->img); -				} -			} -		} -	} -	return Ref<Texture2D>(); -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			if (p_checked) { -				[menu_item setState:NSControlStateValueOn]; -			} else { -				[menu_item setState:NSControlStateValueOff]; -			} -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_CHECK_BOX : CHECKABLE_TYPE_NONE; -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_RADIO_BUTTON : CHECKABLE_TYPE_NONE; -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			obj->callback = p_callback; -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			obj->meta = p_tag; -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			[menu_item setTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]]; -		} -	} -} - -void DisplayServerOSX::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); -	NSMenu *sub_menu = _get_menu_root(p_submenu); -	if (menu && sub_menu) { -		if (sub_menu == menu) { -			ERR_PRINT("Can't set submenu to self!"); -			return; -		} -		if ([sub_menu supermenu]) { -			ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!"); -			return; -		} -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			[menu setSubmenu:sub_menu forItem:menu_item]; -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		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 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) { -	_THREAD_SAFE_METHOD_ - -	NSMenu *menu = _get_menu_root(p_menu_root); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			[menu_item setEnabled:(!p_disabled)]; -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			[menu_item setToolTip:[NSString stringWithUTF8String:p_tooltip.utf8().get_data()]]; -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				obj->state = p_state; -			} -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (obj) { -				obj->max_states = p_max_states; -			} -		} -	} -} - -void DisplayServerOSX::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); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. -			return; -		} -		NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; -		if (menu_item) { -			GodotMenuItem *obj = [menu_item representedObject]; -			if (p_icon.is_valid()) { -				obj->img = p_icon->get_image(); -				obj->img = obj->img->duplicate(); -				if (obj->img->is_compressed()) { -					obj->img->decompress(); -				} -				obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS); -				[menu_item setImage:_convert_to_nsimg(obj->img)]; -			} else { -				obj->img = Ref<Image>(); -				[menu_item setImage:nil]; -			} -		} -	} -} - -int DisplayServerOSX::global_menu_get_item_count(const String &p_menu_root) const { -	_THREAD_SAFE_METHOD_ - -	const NSMenu *menu = _get_menu_root(p_menu_root); -	if (menu) { -		return [menu numberOfItems]; -	} else { -		return 0; -	} -} - -void DisplayServerOSX::global_menu_remove_item(const String &p_menu_root, int p_idx) { -	_THREAD_SAFE_METHOD_ - -	NSMenu *menu = _get_menu_root(p_menu_root); -	if (menu) { -		if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not delete Apple menu. -			return; -		} -		[menu removeItemAtIndex:p_idx]; -	} -} - -void DisplayServerOSX::global_menu_clear(const String &p_menu_root) { -	_THREAD_SAFE_METHOD_ - -	NSMenu *menu = _get_menu_root(p_menu_root); -	if (menu) { -		[menu removeAllItems]; -		// Restore Apple menu. -		if (menu == [NSApp mainMenu]) { -			NSMenuItem *menu_item = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; -			[menu setSubmenu:apple_menu forItem:menu_item]; -		} -	} -} - -bool DisplayServerOSX::tts_is_speaking() const { -	ERR_FAIL_COND_V(!tts, false); -	return [tts isSpeaking]; -} - -bool DisplayServerOSX::tts_is_paused() const { -	ERR_FAIL_COND_V(!tts, false); -	return [tts isPaused]; -} - -Array DisplayServerOSX::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) { -	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() { -	ERR_FAIL_COND(!tts); -	[tts pauseSpeaking]; -} - -void DisplayServerOSX::tts_resume() { -	ERR_FAIL_COND(!tts); -	[tts resumeSpeaking]; -} - -void DisplayServerOSX::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) { -	_THREAD_SAFE_METHOD_ - -	NSAlert *window = [[NSAlert alloc] init]; -	NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()]; -	NSString *ns_description = [NSString stringWithUTF8String:p_description.utf8().get_data()]; - -	for (int i = 0; i < p_buttons.size(); i++) { -		NSString *ns_button = [NSString stringWithUTF8String:p_buttons[i].utf8().get_data()]; -		[window addButtonWithTitle:ns_button]; -	} -	[window setMessageText:ns_title]; -	[window setInformativeText:ns_description]; -	[window setAlertStyle:NSAlertStyleInformational]; - -	int button_pressed; -	NSInteger ret = [window runModal]; -	if (ret == NSAlertFirstButtonReturn) { -		button_pressed = 0; -	} else if (ret == NSAlertSecondButtonReturn) { -		button_pressed = 1; -	} else if (ret == NSAlertThirdButtonReturn) { -		button_pressed = 2; -	} else { -		button_pressed = 2 + (ret - NSAlertThirdButtonReturn); -	} - -	if (!p_callback.is_null()) { -		Variant button = button_pressed; -		Variant *buttonp = &button; -		Variant ret; -		Callable::CallError ce; -		p_callback.call((const Variant **)&buttonp, 1, ret, ce); -	} - -	return OK; -} - -Error DisplayServerOSX::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { -	_THREAD_SAFE_METHOD_ - -	NSAlert *window = [[NSAlert alloc] init]; -	NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()]; -	NSString *ns_description = [NSString stringWithUTF8String:p_description.utf8().get_data()]; -	NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 250, 30)]; - -	[window addButtonWithTitle:@"OK"]; -	[window setMessageText:ns_title]; -	[window setInformativeText:ns_description]; -	[window setAlertStyle:NSAlertStyleInformational]; - -	[input setStringValue:[NSString stringWithUTF8String:p_partial.utf8().get_data()]]; -	[window setAccessoryView:input]; - -	[window runModal]; - -	String ret; -	ret.parse_utf8([[input stringValue] UTF8String]); - -	if (!p_callback.is_null()) { -		Variant text = ret; -		Variant *textp = &text; -		Variant ret; -		Callable::CallError ce; -		p_callback.call((const Variant **)&textp, 1, ret, ce); -	} - -	return OK; -} - -void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) { -	_THREAD_SAFE_METHOD_ - -	if (p_mode == mouse_mode) { -		return; -	} - -	WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; -	WindowData &wd = windows[window_id]; -	if (p_mode == MOUSE_MODE_CAPTURED) { -		// Apple Docs state that the display parameter is not used. -		// "This parameter is not used. By default, you may pass kCGDirectMainDisplay." -		// https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/Quartz_Services_Ref/Reference/reference.html -		if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { -			CGDisplayHideCursor(kCGDirectMainDisplay); -		} -		CGAssociateMouseAndMouseCursorPosition(false); -		[wd.window_object setMovable:NO]; -		const NSRect contentRect = [wd.window_view frame]; -		NSRect pointInWindowRect = NSMakeRect(contentRect.size.width / 2, contentRect.size.height / 2, 0, 0); -		NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin; -		CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y }; -		CGWarpMouseCursorPosition(lMouseWarpPos); -	} else if (p_mode == MOUSE_MODE_HIDDEN) { -		if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { -			CGDisplayHideCursor(kCGDirectMainDisplay); -		} -		[wd.window_object setMovable:YES]; -		CGAssociateMouseAndMouseCursorPosition(true); -	} else if (p_mode == MOUSE_MODE_CONFINED) { -		CGDisplayShowCursor(kCGDirectMainDisplay); -		[wd.window_object setMovable:NO]; -		CGAssociateMouseAndMouseCursorPosition(false); -	} else if (p_mode == MOUSE_MODE_CONFINED_HIDDEN) { -		if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { -			CGDisplayHideCursor(kCGDirectMainDisplay); -		} -		[wd.window_object setMovable:NO]; -		CGAssociateMouseAndMouseCursorPosition(false); -	} else { // MOUSE_MODE_VISIBLE -		CGDisplayShowCursor(kCGDirectMainDisplay); -		[wd.window_object setMovable:YES]; -		CGAssociateMouseAndMouseCursorPosition(true); -	} - -	last_warp = [[NSProcessInfo processInfo] systemUptime]; -	ignore_warp = true; -	warp_events.clear(); -	mouse_mode = p_mode; - -	if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { -		cursor_update_shape(); -	} -} - -DisplayServer::MouseMode DisplayServerOSX::mouse_get_mode() const { -	return mouse_mode; -} - -bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSPoint &r_mpos, NSTimeInterval p_timestamp) { -	_THREAD_SAFE_METHOD_ - -	if (ignore_warp) { -		// Discard late events, before warp. -		if (p_timestamp < last_warp) { -			return true; -		} -		ignore_warp = false; -		return true; -	} - -	if (mouse_mode == DisplayServer::MOUSE_MODE_CONFINED || mouse_mode == DisplayServer::MOUSE_MODE_CONFINED_HIDDEN) { -		// Discard late events. -		if (p_timestamp < last_warp) { -			return true; -		} - -		// Warp affects next event delta, subtract previous warp deltas. -		List<WarpEvent>::Element *F = warp_events.front(); -		while (F) { -			if (F->get().timestamp < p_timestamp) { -				List<DisplayServerOSX::WarpEvent>::Element *E = F; -				r_delta.x -= E->get().delta.x; -				r_delta.y -= E->get().delta.y; -				F = F->next(); -				warp_events.erase(E); -			} else { -				F = F->next(); -			} -		} - -		// Confine mouse position to the window, and update delta. -		NSRect frame = [p_wd.window_object frame]; -		NSPoint conf_pos = r_mpos; -		conf_pos.x = CLAMP(conf_pos.x + r_delta.x, 0.f, frame.size.width); -		conf_pos.y = CLAMP(conf_pos.y - r_delta.y, 0.f, frame.size.height); -		r_delta.x = conf_pos.x - r_mpos.x; -		r_delta.y = r_mpos.y - conf_pos.y; -		r_mpos = conf_pos; - -		// Move mouse cursor. -		NSRect point_in_window_rect = NSMakeRect(conf_pos.x, conf_pos.y, 0, 0); -		conf_pos = [[p_wd.window_view window] convertRectToScreen:point_in_window_rect].origin; -		conf_pos.y = CGDisplayBounds(CGMainDisplayID()).size.height - conf_pos.y; -		CGWarpMouseCursorPosition(conf_pos); - -		// Save warp data. -		last_warp = [[NSProcessInfo processInfo] systemUptime]; - -		DisplayServerOSX::WarpEvent ev; -		ev.timestamp = last_warp; -		ev.delta = r_delta; -		warp_events.push_back(ev); -	} - -	return false; -} - -void DisplayServerOSX::warp_mouse(const Point2i &p_position) { -	_THREAD_SAFE_METHOD_ - -	if (mouse_mode != MOUSE_MODE_CAPTURED) { -		WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; -		WindowData &wd = windows[window_id]; - -		// Local point in window coords. -		const NSRect contentRect = [wd.window_view frame]; -		const float scale = screen_get_max_scale(); -		NSRect pointInWindowRect = NSMakeRect(p_position.x / scale, contentRect.size.height - (p_position.y / scale - 1), 0, 0); -		NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin; - -		// Point in scren coords. -		CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y }; - -		// Do the warping. -		CGEventSourceRef lEventRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState); -		CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0); -		CGAssociateMouseAndMouseCursorPosition(false); -		CGWarpMouseCursorPosition(lMouseWarpPos); -		if (mouse_mode != MOUSE_MODE_CONFINED && mouse_mode != MOUSE_MODE_CONFINED_HIDDEN) { -			CGAssociateMouseAndMouseCursorPosition(true); -		} -	} -} - -Point2i DisplayServerOSX::mouse_get_position() const { -	_THREAD_SAFE_METHOD_ - -	const NSPoint mouse_pos = [NSEvent mouseLocation]; -	const float scale = screen_get_max_scale(); - -	for (NSScreen *screen in [NSScreen screens]) { -		NSRect frame = [screen frame]; -		if (NSMouseInRect(mouse_pos, frame, NO)) { -			Vector2i pos = Vector2i((int)mouse_pos.x, (int)mouse_pos.y); -			pos *= scale; -			pos -= _get_screens_origin(); -			pos.y *= -1; -			return pos; -		} -	} -	return Vector2i(); -} - -void DisplayServerOSX::mouse_set_button_state(MouseButton p_state) { -	last_button_state = p_state; -} - -MouseButton DisplayServerOSX::mouse_get_button_state() const { -	return last_button_state; -} - -void DisplayServerOSX::clipboard_set(const String &p_text) { -	_THREAD_SAFE_METHOD_ - -	NSString *copiedString = [NSString stringWithUTF8String:p_text.utf8().get_data()]; -	NSArray *copiedStringArray = [NSArray arrayWithObject:copiedString]; - -	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; -	[pasteboard clearContents]; -	[pasteboard writeObjects:copiedStringArray]; -} - -String DisplayServerOSX::clipboard_get() const { -	_THREAD_SAFE_METHOD_ - -	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; -	NSArray *classArray = [NSArray arrayWithObject:[NSString class]]; -	NSDictionary *options = [NSDictionary dictionary]; - -	BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options]; - -	if (!ok) { -		return ""; -	} - -	NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options]; -	NSString *string = [objectsToPaste objectAtIndex:0]; - -	String ret; -	ret.parse_utf8([string UTF8String]); -	return ret; -} - -int DisplayServerOSX::get_screen_count() const { -	_THREAD_SAFE_METHOD_ - -	NSArray *screenArray = [NSScreen screens]; -	return [screenArray count]; -} - -Point2i DisplayServerOSX::screen_get_position(int p_screen) const { -	_THREAD_SAFE_METHOD_ - -	if (p_screen == SCREEN_OF_MAIN_WINDOW) { -		p_screen = window_get_current_screen(); -	} - -	Point2i position = _get_native_screen_position(p_screen) - _get_screens_origin(); -	// OS X native y-coordinate relative to _get_screens_origin() is negative, -	// Godot expects a positive value. -	position.y *= -1; -	return position; -} - -Size2i DisplayServerOSX::screen_get_size(int p_screen) const { -	_THREAD_SAFE_METHOD_ - -	if (p_screen == SCREEN_OF_MAIN_WINDOW) { -		p_screen = window_get_current_screen(); -	} - -	NSArray *screenArray = [NSScreen screens]; -	if ((NSUInteger)p_screen < [screenArray count]) { -		// Note: Use frame to get the whole screen size. -		NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame]; -		return Size2i(nsrect.size.width, nsrect.size.height) * screen_get_max_scale(); -	} - -	return Size2i(); -} - -int DisplayServerOSX::screen_get_dpi(int p_screen) const { -	_THREAD_SAFE_METHOD_ - -	if (p_screen == SCREEN_OF_MAIN_WINDOW) { -		p_screen = window_get_current_screen(); -	} - -	NSArray *screenArray = [NSScreen screens]; -	if ((NSUInteger)p_screen < [screenArray count]) { -		NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription]; - -		const NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue]; -		const CGSize displayPhysicalSize = CGDisplayScreenSize([[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); -		float scale = [[screenArray objectAtIndex:p_screen] backingScaleFactor]; - -		float den2 = (displayPhysicalSize.width / 25.4f) * (displayPhysicalSize.width / 25.4f) + (displayPhysicalSize.height / 25.4f) * (displayPhysicalSize.height / 25.4f); -		if (den2 > 0.0f) { -			return ceil(sqrt(displayPixelSize.width * displayPixelSize.width + displayPixelSize.height * displayPixelSize.height) / sqrt(den2) * scale); -		} -	} - -	return 72; -} - -float DisplayServerOSX::screen_get_scale(int p_screen) const { -	_THREAD_SAFE_METHOD_ - -	if (p_screen == SCREEN_OF_MAIN_WINDOW) { -		p_screen = window_get_current_screen(); -	} -	if (OS::get_singleton()->is_hidpi_allowed()) { -		NSArray *screenArray = [NSScreen screens]; -		if ((NSUInteger)p_screen < [screenArray count]) { -			if ([[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) { -				return fmax(1.0, [[screenArray objectAtIndex:p_screen] backingScaleFactor]); -			} -		} -	} - -	return 1.f; -} - -float DisplayServerOSX::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 { -	_THREAD_SAFE_METHOD_ - -	if (p_screen == SCREEN_OF_MAIN_WINDOW) { -		p_screen = window_get_current_screen(); -	} - -	NSArray *screenArray = [NSScreen screens]; -	if ((NSUInteger)p_screen < [screenArray count]) { -		const float scale = screen_get_max_scale(); -		NSRect nsrect = [[screenArray objectAtIndex:p_screen] visibleFrame]; - -		Point2i position = Point2i(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * scale - _get_screens_origin(); -		position.y *= -1; -		Size2i size = Size2i(nsrect.size.width, nsrect.size.height) * scale; - -		return Rect2i(position, size); -	} - -	return Rect2i(); -} - -float DisplayServerOSX::screen_get_refresh_rate(int p_screen) const { -	_THREAD_SAFE_METHOD_ - -	if (p_screen == SCREEN_OF_MAIN_WINDOW) { -		p_screen = window_get_current_screen(); -	} - -	NSArray *screenArray = [NSScreen screens]; -	if ((NSUInteger)p_screen < [screenArray count]) { -		NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription]; -		const CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode([[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); -		const double displayRefreshRate = CGDisplayModeGetRefreshRate(displayMode); -		return (float)displayRefreshRate; -	} -	ERR_PRINT("An error occurred while trying to get the screen refresh rate."); -	return SCREEN_REFRESH_RATE_FALLBACK; -} - -Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const { -	_THREAD_SAFE_METHOD_ - -	Vector<int> ret; -	for (const KeyValue<WindowID, WindowData> &E : windows) { -		ret.push_back(E.key); -	} -	return ret; -} - -DisplayServer::WindowID DisplayServerOSX::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); -	for (int i = 0; i < WINDOW_FLAG_MAX; i++) { -		if (p_flags & (1 << i)) { -			window_set_flag(WindowFlags(i), true, id); -		} -	} - -	return id; -} - -void DisplayServerOSX::show_window(WindowID p_id) { -	WindowData &wd = windows[p_id]; - -	popup_open(p_id); -	if (wd.no_focus || wd.is_popup) { -		[wd.window_object orderFront:nil]; -	} else { -		[wd.window_object makeKeyAndOrderFront:nil]; -	} -} - -void DisplayServerOSX::delete_sub_window(WindowID p_id) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_id)); -	ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted"); - -	WindowData &wd = windows[p_id]; - -	[wd.window_object setContentView:nil]; -	[wd.window_object close]; -} - -void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; -	wd.rect_changed_callback = p_callable; -} - -void DisplayServerOSX::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; -	wd.event_callback = p_callable; -} - -void DisplayServerOSX::window_set_input_event_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_event_callback = p_callable; -} - -void DisplayServerOSX::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) { -	_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) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[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) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	wd.mpath = p_region; -} - -int DisplayServerOSX::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]; - -	const NSUInteger index = [[NSScreen screens] indexOfObject:[wd.window_object screen]]; -	return (index == NSNotFound) ? 0 : index; -} - -void DisplayServerOSX::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. -		[wd.window_object toggleFullScreen:nil]; -		was_fullscreen = true; -	} - -	Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); -	window_set_position(wpos + screen_get_position(p_screen), p_window); - -	if (was_fullscreen) { -		// Re-enter fullscreen mode. -		[wd.window_object toggleFullScreen:nil]; -	} -} - -void DisplayServerOSX::window_set_exclusive(WindowID p_window, bool p_exclusive) { -	_THREAD_SAFE_METHOD_ -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; -	if (wd.exclusive != p_exclusive) { -		wd.exclusive = p_exclusive; -		if (wd.transient_parent != INVALID_WINDOW_ID) { -			WindowData &wd_parent = windows[wd.transient_parent]; -			if (wd.exclusive) { -				ERR_FAIL_COND_MSG([[wd_parent.window_object childWindows] count] > 0, "Transient parent has another exclusive child."); -				[wd_parent.window_object addChildWindow:wd.window_object ordered:NSWindowAbove]; -			} else { -				[wd_parent.window_object removeChildWindow:wd.window_object]; -			} -		} -	} -} - -Point2i DisplayServerOSX::window_get_position(WindowID p_window) const { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND_V(!windows.has(p_window), Point2i()); -	const WindowData &wd = windows[p_window]; - -	// Use content rect position (without titlebar / window border). -	const NSRect contentRect = [wd.window_view frame]; -	const NSRect nsrect = [wd.window_object convertRectToScreen:contentRect]; -	Point2i pos; - -	// Return the position of the top-left corner, for OS X the y starts at the bottom. -	const float scale = screen_get_max_scale(); -	pos.x = nsrect.origin.x; -	pos.y = (nsrect.origin.y + nsrect.size.height); -	pos *= scale; -	pos -= _get_screens_origin(); -	// OS X native y-coordinate relative to _get_screens_origin() is negative, -	// Godot expects a positive value. -	pos.y *= -1; -	return pos; -} - -void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	Point2i position = p_position; -	// OS X native y-coordinate relative to _get_screens_origin() is negative, -	// Godot passes a positive value. -	position.y *= -1; -	position += _get_screens_origin(); -	position /= screen_get_max_scale(); - -	// Remove titlebar / window border size. -	const NSRect contentRect = [wd.window_view frame]; -	const NSRect windowRect = [wd.window_object frame]; -	const NSRect nsrect = [wd.window_object convertRectToScreen:contentRect]; -	Point2i offset; -	offset.x = (nsrect.origin.x - windowRect.origin.x); -	offset.y = (nsrect.origin.y + nsrect.size.height); -	offset.y -= (windowRect.origin.y + windowRect.size.height); - -	[wd.window_object setFrameTopLeftPoint:NSMakePoint(position.x - offset.x, position.y - offset.y)]; - -	_update_window_style(wd); -	update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); -} - -void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent) { -	_THREAD_SAFE_METHOD_ -	ERR_FAIL_COND(p_window == p_parent); - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd_window = windows[p_window]; - -	ERR_FAIL_COND(wd_window.transient_parent == p_parent); - -	ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient."); -	if (p_parent == INVALID_WINDOW_ID) { -		// Remove transient. -		ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID); -		ERR_FAIL_COND(!windows.has(wd_window.transient_parent)); - -		WindowData &wd_parent = windows[wd_window.transient_parent]; - -		wd_window.transient_parent = INVALID_WINDOW_ID; -		wd_parent.transient_children.erase(p_window); -		[wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - -		if (wd_window.exclusive) { -			[wd_parent.window_object removeChildWindow:wd_window.window_object]; -		} -	} else { -		ERR_FAIL_COND(!windows.has(p_parent)); -		ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent"); -		WindowData &wd_parent = windows[p_parent]; - -		wd_window.transient_parent = p_parent; -		wd_parent.transient_children.insert(p_window); -		[wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; - -		if (wd_window.exclusive) { -			[wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove]; -		} -	} -} - -void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	if ((p_size != Size2i()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) { -		ERR_PRINT("Maximum window size can't be smaller than minimum window size!"); -		return; -	} -	wd.max_size = p_size; - -	if ((wd.max_size != Size2i()) && !wd.fullscreen) { -		Size2i size = wd.max_size / screen_get_max_scale(); -		[wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)]; -	} else { -		[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; -	} -} - -Size2i DisplayServerOSX::window_get_max_size(WindowID p_window) const { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); -	const WindowData &wd = windows[p_window]; -	return wd.max_size; -} - -void DisplayServerOSX::window_set_min_size(const Size2i p_size, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	if ((p_size != Size2i()) && (wd.max_size != Size2i()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) { -		ERR_PRINT("Minimum window size can't be larger than maximum window size!"); -		return; -	} -	wd.min_size = p_size; - -	if ((wd.min_size != Size2i()) && !wd.fullscreen) { -		Size2i size = wd.min_size / screen_get_max_scale(); -		[wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)]; -	} else { -		[wd.window_object setContentMinSize:NSMakeSize(0, 0)]; -	} -} - -Size2i DisplayServerOSX::window_get_min_size(WindowID p_window) const { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); -	const WindowData &wd = windows[p_window]; - -	return wd.min_size; -} - -void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	Size2i size = p_size / screen_get_max_scale(); - -	NSPoint top_left; -	NSRect old_frame = [wd.window_object frame]; -	top_left.x = old_frame.origin.x; -	top_left.y = NSMaxY(old_frame); - -	NSRect new_frame = NSMakeRect(0, 0, size.x, size.y); -	new_frame = [wd.window_object frameRectForContentRect:new_frame]; - -	new_frame.origin.x = top_left.x; -	new_frame.origin.y = top_left.y - new_frame.size.height; - -	[wd.window_object setFrame:new_frame display:YES]; - -	_update_window_style(wd); -} - -Size2i DisplayServerOSX::window_get_size(WindowID p_window) const { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); -	const WindowData &wd = windows[p_window]; -	return wd.size; -} - -Size2i DisplayServerOSX::window_get_real_size(WindowID p_window) const { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); -	const WindowData &wd = windows[p_window]; -	NSRect frame = [wd.window_object frame]; -	return Size2i(frame.size.width, frame.size.height) * screen_get_max_scale(); -} - -void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	WindowMode old_mode = window_get_mode(p_window); -	if (old_mode == p_mode) { -		return; // Do nothing. -	} - -	switch (old_mode) { -		case WINDOW_MODE_WINDOWED: { -			// Do nothing. -		} break; -		case WINDOW_MODE_MINIMIZED: { -			[wd.window_object deminiaturize:nil]; -		} break; -		case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: -		case WINDOW_MODE_FULLSCREEN: { -			[(NSWindow *)wd.window_object setLevel:NSNormalWindowLevel]; -			_set_window_per_pixel_transparency_enabled(true, p_window); -			if (wd.resize_disabled) { // Restore resize disabled. -				[wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable]; -			} -			if (wd.min_size != Size2i()) { -				Size2i size = wd.min_size / screen_get_max_scale(); -				[wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)]; -			} -			if (wd.max_size != Size2i()) { -				Size2i size = wd.max_size / screen_get_max_scale(); -				[wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)]; -			} -			[wd.window_object toggleFullScreen:nil]; -			wd.fullscreen = false; -		} break; -		case WINDOW_MODE_MAXIMIZED: { -			if ([wd.window_object isZoomed]) { -				[wd.window_object zoom:nil]; -			} -		} break; -	} - -	switch (p_mode) { -		case WINDOW_MODE_WINDOWED: { -			// Do nothing. -		} break; -		case WINDOW_MODE_MINIMIZED: { -			[wd.window_object performMiniaturize:nil]; -		} break; -		case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: -		case WINDOW_MODE_FULLSCREEN: { -			_set_window_per_pixel_transparency_enabled(false, p_window); -			if (wd.resize_disabled) { // Fullscreen window should be resizable to work. -				[wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable]; -			} -			[wd.window_object setContentMinSize:NSMakeSize(0, 0)]; -			[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; -			[wd.window_object toggleFullScreen:nil]; -			wd.fullscreen = true; -		} break; -		case WINDOW_MODE_MAXIMIZED: { -			if (![wd.window_object isZoomed]) { -				[wd.window_object zoom:nil]; -			} -		} break; -	} -} - -DisplayServer::WindowMode DisplayServerOSX::window_get_mode(WindowID p_window) const { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED); -	const WindowData &wd = windows[p_window]; - -	if (wd.fullscreen) { // If fullscreen, it's not in another mode. -		return WINDOW_MODE_FULLSCREEN; -	} -	if ([wd.window_object isZoomed] && !wd.resize_disabled) { -		return WINDOW_MODE_MAXIMIZED; -	} -	if ([wd.window_object respondsToSelector:@selector(isMiniaturized)]) { -		if ([wd.window_object isMiniaturized]) { -			return WINDOW_MODE_MINIMIZED; -		} -	} - -	// All other discarded, return windowed. -	return WINDOW_MODE_WINDOWED; -} - -bool DisplayServerOSX::window_is_maximize_allowed(WindowID p_window) const { -	return true; -} - -void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	switch (p_flag) { -		case WINDOW_FLAG_RESIZE_DISABLED: { -			wd.resize_disabled = p_enabled; -			if (wd.fullscreen) { // Fullscreen window should be resizable, style will be applied on exiting fullscreen. -				return; -			} -			if (p_enabled) { -				[wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable]; -			} else { -				[wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable]; -			} -		} break; -		case WINDOW_FLAG_BORDERLESS: { -			// OrderOut prevents a lose focus bug with the window. -			if ([wd.window_object isVisible]) { -				[wd.window_object orderOut:nil]; -			} -			wd.borderless = p_enabled; -			if (p_enabled) { -				[wd.window_object setStyleMask:NSWindowStyleMaskBorderless]; -			} else { -				_set_window_per_pixel_transparency_enabled(false, p_window); -				[wd.window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (wd.resize_disabled ? 0 : NSWindowStyleMaskResizable)]; -				// Force update of the window styles. -				NSRect frameRect = [wd.window_object frame]; -				[wd.window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO]; -				[wd.window_object setFrame:frameRect display:NO]; -			} -			_update_window_style(wd); -			if ([wd.window_object isVisible]) { -				if (wd.no_focus || wd.is_popup) { -					[wd.window_object orderFront:nil]; -				} else { -					[wd.window_object makeKeyAndOrderFront:nil]; -				} -			} -		} break; -		case WINDOW_FLAG_ALWAYS_ON_TOP: { -			wd.on_top = p_enabled; -			if (wd.fullscreen) { -				return; -			} -			if (p_enabled) { -				[(NSWindow *)wd.window_object setLevel:NSFloatingWindowLevel]; -			} else { -				[(NSWindow *)wd.window_object setLevel:NSNormalWindowLevel]; -			} -		} break; -		case WINDOW_FLAG_TRANSPARENT: { -			if (p_enabled) { -				[wd.window_object setStyleMask:NSWindowStyleMaskBorderless]; // Force borderless. -			} else if (!wd.borderless) { -				[wd.window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (wd.resize_disabled ? 0 : NSWindowStyleMaskResizable)]; -			} -			_set_window_per_pixel_transparency_enabled(p_enabled, p_window); -		} break; -		case WINDOW_FLAG_NO_FOCUS: { -			wd.no_focus = p_enabled; -		} break; -		case WINDOW_FLAG_POPUP: { -			ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup."); -			ERR_FAIL_COND_MSG([wd.window_object isVisible] && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened."); -			wd.is_popup = p_enabled; -		} break; -		default: { -		} -	} -} - -bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) const { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND_V(!windows.has(p_window), false); -	const WindowData &wd = windows[p_window]; - -	switch (p_flag) { -		case WINDOW_FLAG_RESIZE_DISABLED: { -			return wd.resize_disabled; -		} break; -		case WINDOW_FLAG_BORDERLESS: { -			return [wd.window_object styleMask] == NSWindowStyleMaskBorderless; -		} break; -		case WINDOW_FLAG_ALWAYS_ON_TOP: { -			if (wd.fullscreen) { -				return wd.on_top; -			} else { -				return [(NSWindow *)wd.window_object level] == NSFloatingWindowLevel; -			} -		} break; -		case WINDOW_FLAG_TRANSPARENT: { -			return wd.layered_window; -		} break; -		case WINDOW_FLAG_NO_FOCUS: { -			return wd.no_focus; -		} break; -		case WINDOW_FLAG_POPUP: { -			return wd.is_popup; -		} break; -		default: { -		} -	} - -	return false; -} - -void DisplayServerOSX::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) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	const WindowData &wd = windows[p_window]; - -	[[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; -	if (wd.no_focus || wd.is_popup) { -		[wd.window_object orderFront:nil]; -	} else { -		[wd.window_object makeKeyAndOrderFront:nil]; -	} -} - -bool DisplayServerOSX::window_can_draw(WindowID p_window) const { -	return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED; -} - -bool DisplayServerOSX::can_any_window_draw() const { -	_THREAD_SAFE_METHOD_ - -	for (const KeyValue<WindowID, WindowData> &E : windows) { -		if (window_get_mode(E.key) != WINDOW_MODE_MINIMIZED) { -			return true; -		} -	} -	return false; -} - -void DisplayServerOSX::window_set_ime_active(const bool p_active, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	wd.im_active = p_active; - -	if (!p_active) { -		[wd.window_view cancelComposition]; -	} -} - -void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; - -	wd.im_position = p_pos; -} - -DisplayServer::WindowID DisplayServerOSX::get_window_at_screen_position(const Point2i &p_position) const { -	Point2i position = p_position; -	position.y *= -1; -	position += _get_screens_origin(); -	position /= screen_get_max_scale(); - -	NSInteger wnum = [NSWindow windowNumberAtPoint:NSMakePoint(position.x, position.y) belowWindowWithWindowNumber:0 /*topmost*/]; -	for (const KeyValue<WindowID, WindowData> &E : windows) { -		if ([E.value.window_object windowNumber] == wnum) { -			return E.key; -		} -	} -	return INVALID_WINDOW_ID; -} - -int64_t DisplayServerOSX::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: { -			return 0; // Not supported. -		} -		case WINDOW_HANDLE: { -			return (int64_t)windows[p_window].window_object; -		} -		case WINDOW_VIEW: { -			return (int64_t)windows[p_window].window_view; -		} -		default: { -			return 0; -		} -	} -} - -void DisplayServerOSX::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 { -	_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) { -#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) { -	_THREAD_SAFE_METHOD_ -#if defined(GLES3_ENABLED) -	if (gl_manager) { -		gl_manager->set_use_vsync(p_vsync_mode); -	} -#endif -#if defined(VULKAN_ENABLED) -	if (context_vulkan) { -		context_vulkan->set_vsync_mode(p_window, p_vsync_mode); -	} -#endif -} - -DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_window) const { -	_THREAD_SAFE_METHOD_ -#if defined(GLES3_ENABLED) -	if (gl_manager) { -		return (gl_manager->is_using_vsync() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED); -	} -#endif -#if defined(VULKAN_ENABLED) -	if (context_vulkan) { -		return context_vulkan->get_vsync_mode(p_window); -	} -#endif -	return DisplayServer::VSYNC_ENABLED; -} - -Point2i DisplayServerOSX::ime_get_selection() const { -	return im_selection; -} - -String DisplayServerOSX::ime_get_text() const { -	return im_text; -} - -void DisplayServerOSX::cursor_update_shape() { -	_THREAD_SAFE_METHOD_ - -	if (cursors[cursor_shape] != nullptr) { -		[cursors[cursor_shape] set]; -	} else { -		switch (cursor_shape) { -			case CURSOR_ARROW: -				[[NSCursor arrowCursor] set]; -				break; -			case CURSOR_IBEAM: -				[[NSCursor IBeamCursor] set]; -				break; -			case CURSOR_POINTING_HAND: -				[[NSCursor pointingHandCursor] set]; -				break; -			case CURSOR_CROSS: -				[[NSCursor crosshairCursor] set]; -				break; -			case CURSOR_WAIT: -				[[NSCursor arrowCursor] set]; -				break; -			case CURSOR_BUSY: -				[[NSCursor arrowCursor] set]; -				break; -			case CURSOR_DRAG: -				[[NSCursor closedHandCursor] set]; -				break; -			case CURSOR_CAN_DROP: -				[[NSCursor openHandCursor] set]; -				break; -			case CURSOR_FORBIDDEN: -				[[NSCursor operationNotAllowedCursor] set]; -				break; -			case CURSOR_VSIZE: -				[_cursor_from_selector(@selector(_windowResizeNorthSouthCursor), @selector(resizeUpDownCursor)) set]; -				break; -			case CURSOR_HSIZE: -				[_cursor_from_selector(@selector(_windowResizeEastWestCursor), @selector(resizeLeftRightCursor)) set]; -				break; -			case CURSOR_BDIAGSIZE: -				[_cursor_from_selector(@selector(_windowResizeNorthEastSouthWestCursor)) set]; -				break; -			case CURSOR_FDIAGSIZE: -				[_cursor_from_selector(@selector(_windowResizeNorthWestSouthEastCursor)) set]; -				break; -			case CURSOR_MOVE: -				[[NSCursor arrowCursor] set]; -				break; -			case CURSOR_VSPLIT: -				[[NSCursor resizeUpDownCursor] set]; -				break; -			case CURSOR_HSPLIT: -				[[NSCursor resizeLeftRightCursor] set]; -				break; -			case CURSOR_HELP: -				[_cursor_from_selector(@selector(_helpCursor)) set]; -				break; -			default: { -			} -		} -	} -} - -void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_INDEX(p_shape, CURSOR_MAX); - -	if (cursor_shape == p_shape) { -		return; -	} - -	cursor_shape = p_shape; - -	if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) { -		return; -	} - -	cursor_update_shape(); -} - -DisplayServerOSX::CursorShape DisplayServerOSX::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) { -	_THREAD_SAFE_METHOD_ - -	if (p_cursor.is_valid()) { -		HashMap<CursorShape, Vector<Variant>>::Iterator cursor_c = cursors_cache.find(p_shape); - -		if (cursor_c) { -			if (cursor_c->value[0] == p_cursor && cursor_c->value[1] == p_hotspot) { -				cursor_set_shape(p_shape); -				return; -			} -			cursors_cache.erase(p_shape); -		} - -		Ref<Texture2D> texture = p_cursor; -		Ref<AtlasTexture> atlas_texture = p_cursor; -		Ref<Image> image; -		Size2 texture_size; -		Rect2 atlas_rect; - -		if (texture.is_valid()) { -			image = texture->get_image(); -		} - -		if (!image.is_valid() && atlas_texture.is_valid()) { -			texture = atlas_texture->get_atlas(); - -			atlas_rect.size.width = texture->get_width(); -			atlas_rect.size.height = texture->get_height(); -			atlas_rect.position.x = atlas_texture->get_region().position.x; -			atlas_rect.position.y = atlas_texture->get_region().position.y; - -			texture_size.width = atlas_texture->get_region().size.x; -			texture_size.height = atlas_texture->get_region().size.y; -		} else if (image.is_valid()) { -			texture_size.width = texture->get_width(); -			texture_size.height = texture->get_height(); -		} - -		ERR_FAIL_COND(!texture.is_valid()); -		ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0); -		ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); -		ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height); - -		image = texture->get_image(); - -		ERR_FAIL_COND(!image.is_valid()); - -		NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] -				initWithBitmapDataPlanes:nullptr -							  pixelsWide:int(texture_size.width) -							  pixelsHigh:int(texture_size.height) -						   bitsPerSample:8 -						 samplesPerPixel:4 -								hasAlpha:YES -								isPlanar:NO -						  colorSpaceName:NSDeviceRGBColorSpace -							 bytesPerRow:int(texture_size.width) * 4 -							bitsPerPixel:32]; - -		ERR_FAIL_COND(imgrep == nil); -		uint8_t *pixels = [imgrep bitmapData]; - -		int len = int(texture_size.width * texture_size.height); - -		for (int i = 0; i < len; i++) { -			int row_index = floor(i / texture_size.width) + atlas_rect.position.y; -			int column_index = (i % int(texture_size.width)) + atlas_rect.position.x; - -			if (atlas_texture.is_valid()) { -				column_index = MIN(column_index, atlas_rect.size.width - 1); -				row_index = MIN(row_index, atlas_rect.size.height - 1); -			} - -			uint32_t color = image->get_pixel(column_index, row_index).to_argb32(); - -			uint8_t alpha = (color >> 24) & 0xFF; -			pixels[i * 4 + 0] = ((color >> 16) & 0xFF) * alpha / 255; -			pixels[i * 4 + 1] = ((color >> 8) & 0xFF) * alpha / 255; -			pixels[i * 4 + 2] = ((color)&0xFF) * alpha / 255; -			pixels[i * 4 + 3] = alpha; -		} - -		NSImage *nsimage = [[NSImage alloc] initWithSize:NSMakeSize(texture_size.width, texture_size.height)]; -		[nsimage addRepresentation:imgrep]; - -		NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)]; - -		cursors[p_shape] = cursor; - -		Vector<Variant> params; -		params.push_back(p_cursor); -		params.push_back(p_hotspot); -		cursors_cache.insert(p_shape, params); - -		if (p_shape == cursor_shape) { -			if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { -				[cursor set]; -			} -		} -	} else { -		// Reset to default system cursor. -		if (cursors[p_shape] != nullptr) { -			cursors[p_shape] = nullptr; -		} - -		cursor_update_shape(); - -		cursors_cache.erase(p_shape); -	} -} - -bool DisplayServerOSX::get_swap_cancel_ok() { -	return false; -} - -int DisplayServerOSX::keyboard_get_layout_count() const { -	if (keyboard_layout_dirty) { -		const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); -	} -	return kbd_layouts.size(); -} - -void DisplayServerOSX::keyboard_set_current_layout(int p_index) { -	if (keyboard_layout_dirty) { -		const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); -	} - -	ERR_FAIL_INDEX(p_index, kbd_layouts.size()); - -	NSString *cur_name = [NSString stringWithUTF8String:kbd_layouts[p_index].name.utf8().get_data()]; - -	NSDictionary *filter_kbd = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardLayout }; -	NSArray *list_kbd = (__bridge NSArray *)TISCreateInputSourceList((__bridge CFDictionaryRef)filter_kbd, false); -	for (NSUInteger i = 0; i < [list_kbd count]; i++) { -		NSString *name = (__bridge NSString *)TISGetInputSourceProperty((__bridge TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyLocalizedName); -		if ([name isEqualToString:cur_name]) { -			TISSelectInputSource((__bridge TISInputSourceRef)[list_kbd objectAtIndex:i]); -			break; -		} -	} - -	NSDictionary *filter_ime = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardInputMode }; -	NSArray *list_ime = (__bridge NSArray *)TISCreateInputSourceList((__bridge CFDictionaryRef)filter_ime, false); -	for (NSUInteger i = 0; i < [list_ime count]; i++) { -		NSString *name = (__bridge NSString *)TISGetInputSourceProperty((__bridge TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyLocalizedName); -		if ([name isEqualToString:cur_name]) { -			TISSelectInputSource((__bridge TISInputSourceRef)[list_ime objectAtIndex:i]); -			break; -		} -	} -} - -int DisplayServerOSX::keyboard_get_current_layout() const { -	if (keyboard_layout_dirty) { -		const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); -	} - -	return current_layout; -} - -String DisplayServerOSX::keyboard_get_layout_language(int p_index) const { -	if (keyboard_layout_dirty) { -		const_cast<DisplayServerOSX *>(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 { -	if (keyboard_layout_dirty) { -		const_cast<DisplayServerOSX *>(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 { -	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); -} - -void DisplayServerOSX::process_events() { -	_THREAD_SAFE_METHOD_ - -	while (true) { -		NSEvent *event = [NSApp -				nextEventMatchingMask:NSEventMaskAny -							untilDate:[NSDate distantPast] -							   inMode:NSDefaultRunLoopMode -							  dequeue:YES]; - -		if (event == nil) { -			break; -		} - -		[NSApp sendEvent:event]; -	} - -	if (!drop_events) { -		_process_key_events(); -		Input::get_singleton()->flush_buffered_events(); -	} - -	for (KeyValue<WindowID, WindowData> &E : windows) { -		WindowData &wd = E.value; -		if (wd.mpath.size() > 0) { -			update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); -			if (Geometry2D::is_point_in_polygon(wd.mouse_pos, wd.mpath)) { -				if ([wd.window_object ignoresMouseEvents]) { -					[wd.window_object setIgnoresMouseEvents:NO]; -				} -			} else { -				if (![wd.window_object ignoresMouseEvents]) { -					[wd.window_object setIgnoresMouseEvents:YES]; -				} -			} -		} else { -			if ([wd.window_object ignoresMouseEvents]) { -				[wd.window_object setIgnoresMouseEvents:NO]; -			} -		} -	} -} - -void DisplayServerOSX::force_process_and_drop_events() { -	_THREAD_SAFE_METHOD_ - -	drop_events = true; -	process_events(); -	drop_events = false; -} - -void DisplayServerOSX::release_rendering_thread() { -} - -void DisplayServerOSX::make_rendering_thread() { -} - -void DisplayServerOSX::swap_buffers() { -#if defined(GLES3_ENABLED) -	if (gl_manager) { -		gl_manager->swap_buffers(); -	} -#endif -} - -void DisplayServerOSX::set_native_icon(const String &p_filename) { -	_THREAD_SAFE_METHOD_ - -	Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::READ); -	ERR_FAIL_COND(f.is_null()); - -	Vector<uint8_t> data; -	uint64_t len = f->get_length(); -	data.resize(len); -	f->get_buffer((uint8_t *)&data.write[0], len); - -	NSData *icon_data = [[NSData alloc] initWithBytes:&data.write[0] length:len]; -	ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data."); - -	NSImage *icon = [[NSImage alloc] initWithData:icon_data]; -	ERR_FAIL_COND_MSG(!icon, "Error loading icon."); - -	[NSApp setApplicationIconImage:icon]; -} - -void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { -	_THREAD_SAFE_METHOD_ - -	Ref<Image> img = p_icon; -	img = img->duplicate(); -	img->convert(Image::FORMAT_RGBA8); -	NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] -			initWithBitmapDataPlanes:nullptr -						  pixelsWide:img->get_width() -						  pixelsHigh:img->get_height() -					   bitsPerSample:8 -					 samplesPerPixel:4 -							hasAlpha:YES -							isPlanar:NO -					  colorSpaceName:NSDeviceRGBColorSpace -						 bytesPerRow:img->get_width() * 4 -						bitsPerPixel:32]; -	ERR_FAIL_COND(imgrep == nil); -	uint8_t *pixels = [imgrep bitmapData]; - -	int len = img->get_width() * img->get_height(); -	const uint8_t *r = img->get_data().ptr(); - -	/* Premultiply the alpha channel */ -	for (int i = 0; i < len; i++) { -		uint8_t alpha = r[i * 4 + 3]; -		pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255); -		pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255); -		pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255); -		pixels[i * 4 + 3] = alpha; -	} - -	NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())]; -	ERR_FAIL_COND(nsimg == nil); - -	[nsimg addRepresentation:imgrep]; -	[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)); -	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> drivers; - -#if defined(VULKAN_ENABLED) -	drivers.push_back("vulkan"); -#endif -#if defined(GLES3_ENABLED) -	drivers.push_back("opengl3"); -#endif - -	return drivers; -} - -void DisplayServerOSX::register_osx_driver() { -	register_create_function("osx", create_func, get_rendering_drivers_func); -} - -DisplayServer::WindowID DisplayServerOSX::window_get_active_popup() const { -	const List<WindowID>::Element *E = popup_list.back(); -	if (E) { -		return E->get(); -	} else { -		return INVALID_WINDOW_ID; -	} -} - -void DisplayServerOSX::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND(!windows.has(p_window)); -	WindowData &wd = windows[p_window]; -	wd.parent_safe_rect = p_rect; -} - -Rect2i DisplayServerOSX::window_get_popup_safe_rect(WindowID p_window) const { -	_THREAD_SAFE_METHOD_ - -	ERR_FAIL_COND_V(!windows.has(p_window), Rect2i()); -	const WindowData &wd = windows[p_window]; -	return wd.parent_safe_rect; -} - -void DisplayServerOSX::popup_open(WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	WindowData &wd = windows[p_window]; -	if (wd.is_popup) { -		bool was_empty = popup_list.is_empty(); -		// Find current popup parent, or root popup if new window is not transient. -		List<WindowID>::Element *C = nullptr; -		List<WindowID>::Element *E = popup_list.back(); -		while (E) { -			if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) { -				C = E; -				E = E->prev(); -			} else { -				break; -			} -		} -		if (C) { -			send_window_event(windows[C->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); -		} - -		if (was_empty && popup_list.is_empty()) { -			// Inform OS that popup was opened, to close other native popups. -			[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.beginMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"]; -		} -		time_since_popup = OS::get_singleton()->get_ticks_msec(); -		popup_list.push_back(p_window); -	} -} - -void DisplayServerOSX::popup_close(WindowID p_window) { -	_THREAD_SAFE_METHOD_ - -	bool was_empty = popup_list.is_empty(); -	List<WindowID>::Element *E = popup_list.find(p_window); -	while (E) { -		List<WindowID>::Element *F = E->next(); -		WindowID win_id = E->get(); -		popup_list.erase(E); - -		send_window_event(windows[win_id], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); -		E = F; -	} -	if (!was_empty && popup_list.is_empty()) { -		// Inform OS that all popups are closed. -		[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.endMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"]; -	} -} - -bool DisplayServerOSX::mouse_process_popups(bool p_close) { -	_THREAD_SAFE_METHOD_ - -	bool was_empty = popup_list.is_empty(); -	bool closed = false; -	if (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); -			closed = true; -		} -		if (!was_empty) { -			// Inform OS that all popups are closed. -			[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.endMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"]; -		} -	} else { -		uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup; -		if (delta < 250) { -			return false; -		} - -		Point2i pos = mouse_get_position(); -		List<WindowID>::Element *C = nullptr; -		List<WindowID>::Element *E = popup_list.back(); -		// Find top popup to close. -		while (E) { -			// Popup window area. -			Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get())); -			// Area of the parent window, which responsible for opening sub-menu. -			Rect2i safe_rect = window_get_popup_safe_rect(E->get()); -			if (win_rect.has_point(pos)) { -				break; -			} else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) { -				break; -			} else { -				C = E; -				E = E->prev(); -			} -		} -		if (C) { -			send_window_event(windows[C->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); -			closed = true; -		} -		if (!was_empty && popup_list.is_empty()) { -			// Inform OS that all popups are closed. -			[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.apple.HIToolbox.endMenuTrackingNotification" object:@"org.godotengine.godot.popup_window"]; -		} -	} -	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) { -	Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); - -	r_error = OK; - -	memset(cursors, 0, sizeof(cursors)); - -	event_source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); -	ERR_FAIL_COND(!event_source); - -	CGEventSourceSetLocalEventsSuppressionInterval(event_source, 0.0); - -	int screen_count = get_screen_count(); -	for (int i = 0; i < screen_count; i++) { -		display_max_scale = fmax(display_max_scale, screen_get_scale(i)); -	} - -	// Register to be notified on keyboard layout changes. -	CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), -			nullptr, _keyboard_layout_changed, -			kTISNotifySelectedKeyboardInputSourceChanged, nullptr, -			CFNotificationSuspensionBehaviorDeliverImmediately); - -	// Register to be notified on displays arrangement changes. -	CGDisplayRegisterReconfigurationCallback(_displays_arrangement_changed, nullptr); - -	// Init TTS -	tts = [[TTS_OSX alloc] init]; - -	NSMenuItem *menu_item; -	NSString *title; - -	NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; -	if (nsappname == nil) { -		nsappname = [[NSProcessInfo processInfo] processName]; -	} - -	// Setup Dock menu. -	dock_menu = [[NSMenu alloc] initWithTitle:@"_dock"]; -	[dock_menu setAutoenablesItems:NO]; - -	// Setup Apple menu. -	apple_menu = [[NSMenu alloc] initWithTitle:@""]; -	title = [NSString stringWithFormat:NSLocalizedString(@"About %@", nil), nsappname]; -	[apple_menu addItemWithTitle:title action:@selector(showAbout:) keyEquivalent:@""]; -	[apple_menu setAutoenablesItems:NO]; - -	[apple_menu addItem:[NSMenuItem separatorItem]]; - -	NSMenu *services = [[NSMenu alloc] initWithTitle:@""]; -	menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Services", nil) action:nil keyEquivalent:@""]; -	[apple_menu setSubmenu:services forItem:menu_item]; -	[NSApp setServicesMenu:services]; - -	[apple_menu addItem:[NSMenuItem separatorItem]]; - -	title = [NSString stringWithFormat:NSLocalizedString(@"Hide %@", nil), nsappname]; -	[apple_menu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; - -	menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Hide Others", nil) action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; -	[menu_item setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)]; - -	[apple_menu addItemWithTitle:NSLocalizedString(@"Show all", nil) action:@selector(unhideAllApplications:) keyEquivalent:@""]; - -	[apple_menu addItem:[NSMenuItem separatorItem]]; - -	title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname]; -	[apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; - -	// Add items to the menu bar. -	NSMenu *main_menu = [NSApp mainMenu]; -	menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; -	[main_menu setSubmenu:apple_menu forItem:menu_item]; -	[main_menu setAutoenablesItems:NO]; - -	//!!!!!!!!!!!!!!!!!!!!!!!!!! -	//TODO - do Vulkan and OpenGL support checks, driver selection and fallback -	rendering_driver = p_rendering_driver; - -#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)); -		if (gl_manager->initialize() != OK) { -			memdelete(gl_manager); -			gl_manager = nullptr; -			r_error = ERR_UNAVAILABLE; -			ERR_FAIL_MSG("Could not initialize OpenGL"); -			return; -		} -	} -#endif -#if defined(VULKAN_ENABLED) -	if (rendering_driver == "vulkan") { -		context_vulkan = memnew(VulkanContextOSX); -		if (context_vulkan->initialize() != OK) { -			memdelete(context_vulkan); -			context_vulkan = nullptr; -			r_error = ERR_CANT_CREATE; -			ERR_FAIL_MSG("Could not initialize Vulkan"); -		} -	} -#endif - -	Point2i window_position( -			screen_get_position(0).x + (screen_get_size(0).width - p_resolution.width) / 2, -			screen_get_position(0).y + (screen_get_size(0).height - p_resolution.height) / 2); -	WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution)); -	ERR_FAIL_COND(main_window == INVALID_WINDOW_ID); -	for (int i = 0; i < WINDOW_FLAG_MAX; i++) { -		if (p_flags & (1 << i)) { -			window_set_flag(WindowFlags(i), true, main_window); -		} -	} -	show_window(MAIN_WINDOW_ID); - -#if defined(GLES3_ENABLED) -	if (rendering_driver == "opengl3") { -		RasterizerGLES3::make_current(); -	} -#endif -#if defined(VULKAN_ENABLED) -	if (rendering_driver == "vulkan") { -		rendering_device_vulkan = memnew(RenderingDeviceVulkan); -		rendering_device_vulkan->initialize(context_vulkan); - -		RendererCompositorRD::make_current(); -	} -#endif -} - -DisplayServerOSX::~DisplayServerOSX() { -	// Destroy all windows. -	for (HashMap<WindowID, WindowData>::Iterator E = windows.begin(); E;) { -		HashMap<WindowID, WindowData>::Iterator F = E; -		++E; -		[F->value.window_object setContentView:nil]; -		[F->value.window_object close]; -	} - -	// Destroy drivers. -#if defined(GLES3_ENABLED) -	if (gl_manager) { -		memdelete(gl_manager); -		gl_manager = nullptr; -	} -#endif -#if defined(VULKAN_ENABLED) -	if (rendering_device_vulkan) { -		rendering_device_vulkan->finalize(); -		memdelete(rendering_device_vulkan); -		rendering_device_vulkan = nullptr; -	} - -	if (context_vulkan) { -		memdelete(context_vulkan); -		context_vulkan = nullptr; -	} -#endif - -	CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), nullptr, kTISNotifySelectedKeyboardInputSourceChanged, nullptr); -	CGDisplayRemoveReconfigurationCallback(_displays_arrangement_changed, nullptr); - -	cursors_cache.clear(); -} diff --git a/platform/osx/export/codesign.cpp b/platform/osx/export/codesign.cpp deleted file mode 100644 index fd044c00cc..0000000000 --- a/platform/osx/export/codesign.cpp +++ /dev/null @@ -1,1564 +0,0 @@ -/*************************************************************************/ -/*  codesign.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 "codesign.h" - -#include "lipo.h" -#include "macho.h" -#include "plist.h" - -#include "core/os/os.h" -#include "editor/editor_paths.h" -#include "editor/editor_settings.h" - -#include "modules/modules_enabled.gen.h" // For regex. - -#include <ctime> - -#ifdef MODULE_REGEX_ENABLED - -/*************************************************************************/ -/* CodeSignCodeResources                                                 */ -/*************************************************************************/ - -String CodeSignCodeResources::hash_sha1_base64(const String &p_path) { -	Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::READ); -	ERR_FAIL_COND_V_MSG(fa.is_null(), String(), vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); - -	CryptoCore::SHA1Context ctx; -	ctx.start(); - -	unsigned char step[4096]; -	while (true) { -		uint64_t br = fa->get_buffer(step, 4096); -		if (br > 0) { -			ctx.update(step, br); -		} -		if (br < 4096) { -			break; -		} -	} - -	unsigned char hash[0x14]; -	ctx.finish(hash); - -	return CryptoCore::b64_encode_str(hash, 0x14); -} - -String CodeSignCodeResources::hash_sha256_base64(const String &p_path) { -	Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::READ); -	ERR_FAIL_COND_V_MSG(fa.is_null(), String(), vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); - -	CryptoCore::SHA256Context ctx; -	ctx.start(); - -	unsigned char step[4096]; -	while (true) { -		uint64_t br = fa->get_buffer(step, 4096); -		if (br > 0) { -			ctx.update(step, br); -		} -		if (br < 4096) { -			break; -		} -	} - -	unsigned char hash[0x20]; -	ctx.finish(hash); - -	return CryptoCore::b64_encode_str(hash, 0x20); -} - -void CodeSignCodeResources::add_rule1(const String &p_rule, const String &p_key, int p_weight, bool p_store) { -	rules1.push_back(CRRule(p_rule, p_key, p_weight, p_store)); -} - -void CodeSignCodeResources::add_rule2(const String &p_rule, const String &p_key, int p_weight, bool p_store) { -	rules2.push_back(CRRule(p_rule, p_key, p_weight, p_store)); -} - -CodeSignCodeResources::CRMatch CodeSignCodeResources::match_rules1(const String &p_path) const { -	CRMatch found = CRMatch::CR_MATCH_NO; -	int weight = 0; -	for (int i = 0; i < rules1.size(); i++) { -		RegEx regex = RegEx(rules1[i].file_pattern); -		if (regex.search(p_path).is_valid()) { -			if (rules1[i].key == "omit") { -				return CRMatch::CR_MATCH_NO; -			} else if (rules1[i].key == "nested") { -				if (weight <= rules1[i].weight) { -					found = CRMatch::CR_MATCH_NESTED; -					weight = rules1[i].weight; -				} -			} else if (rules1[i].key == "optional") { -				if (weight <= rules1[i].weight) { -					found = CRMatch::CR_MATCH_OPTIONAL; -					weight = rules1[i].weight; -				} -			} else { -				if (weight <= rules1[i].weight) { -					found = CRMatch::CR_MATCH_YES; -					weight = rules1[i].weight; -				} -			} -		} -	} -	return found; -} - -CodeSignCodeResources::CRMatch CodeSignCodeResources::match_rules2(const String &p_path) const { -	CRMatch found = CRMatch::CR_MATCH_NO; -	int weight = 0; -	for (int i = 0; i < rules2.size(); i++) { -		RegEx regex = RegEx(rules2[i].file_pattern); -		if (regex.search(p_path).is_valid()) { -			if (rules2[i].key == "omit") { -				return CRMatch::CR_MATCH_NO; -			} else if (rules2[i].key == "nested") { -				if (weight <= rules2[i].weight) { -					found = CRMatch::CR_MATCH_NESTED; -					weight = rules2[i].weight; -				} -			} else if (rules2[i].key == "optional") { -				if (weight <= rules2[i].weight) { -					found = CRMatch::CR_MATCH_OPTIONAL; -					weight = rules2[i].weight; -				} -			} else { -				if (weight <= rules2[i].weight) { -					found = CRMatch::CR_MATCH_YES; -					weight = rules2[i].weight; -				} -			} -		} -	} -	return found; -} - -bool CodeSignCodeResources::add_file1(const String &p_root, const String &p_path) { -	CRMatch found = match_rules1(p_path); -	if (found != CRMatch::CR_MATCH_YES && found != CRMatch::CR_MATCH_OPTIONAL) { -		return true; // No match. -	} - -	CRFile f; -	f.name = p_path; -	f.optional = (found == CRMatch::CR_MATCH_OPTIONAL); -	f.nested = false; -	f.hash = hash_sha1_base64(p_root.plus_file(p_path)); -	print_verbose(vformat("CodeSign/CodeResources: File(V1) %s hash1:%s", f.name, f.hash)); - -	files1.push_back(f); -	return true; -} - -bool CodeSignCodeResources::add_file2(const String &p_root, const String &p_path) { -	CRMatch found = match_rules2(p_path); -	if (found == CRMatch::CR_MATCH_NESTED) { -		return add_nested_file(p_root, p_path, p_root.plus_file(p_path)); -	} -	if (found != CRMatch::CR_MATCH_YES && found != CRMatch::CR_MATCH_OPTIONAL) { -		return true; // No match. -	} - -	CRFile f; -	f.name = p_path; -	f.optional = (found == CRMatch::CR_MATCH_OPTIONAL); -	f.nested = false; -	f.hash = hash_sha1_base64(p_root.plus_file(p_path)); -	f.hash2 = hash_sha256_base64(p_root.plus_file(p_path)); - -	print_verbose(vformat("CodeSign/CodeResources: File(V2) %s hash1:%s hash2:%s", f.name, f.hash, f.hash2)); - -	files2.push_back(f); -	return true; -} - -bool CodeSignCodeResources::add_nested_file(const String &p_root, const String &p_path, const String &p_exepath) { -#define CLEANUP()                                       \ -	if (files_to_add.size() > 1) {                      \ -		for (int j = 0; j < files_to_add.size(); j++) { \ -			da->remove(files_to_add[j]);                \ -		}                                               \ -	} - -	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); -	ERR_FAIL_COND_V(da.is_null(), false); - -	Vector<String> files_to_add; -	if (LipO::is_lipo(p_exepath)) { -		String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo"); -		Error err = da->make_dir_recursive(tmp_path_name); -		ERR_FAIL_COND_V_MSG(err != OK, false, vformat("CodeSign/CodeResources: Failed to create \"%s\" subfolder.", tmp_path_name)); -		LipO lip; -		if (lip.open_file(p_exepath)) { -			for (int i = 0; i < lip.get_arch_count(); i++) { -				if (!lip.extract_arch(i, tmp_path_name.plus_file("_rqexe_" + itos(i)))) { -					CLEANUP(); -					ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Failed to extract thin binary."); -				} -				files_to_add.push_back(tmp_path_name.plus_file("_rqexe_" + itos(i))); -			} -		} -	} else if (MachO::is_macho(p_exepath)) { -		files_to_add.push_back(p_exepath); -	} - -	CRFile f; -	f.name = p_path; -	f.optional = false; -	f.nested = true; -	for (int i = 0; i < files_to_add.size(); i++) { -		MachO mh; -		if (!mh.open_file(files_to_add[i])) { -			CLEANUP(); -			ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid executable file."); -		} -		PackedByteArray hash = mh.get_cdhash_sha256(); // Use SHA-256 variant, if available. -		if (hash.size() != 0x20) { -			hash = mh.get_cdhash_sha1(); // Use SHA-1 instead. -			if (hash.size() != 0x14) { -				CLEANUP(); -				ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Unsigned nested executable file."); -			} -		} -		hash.resize(0x14); // Always clamp to 0x14 size. -		f.hash = CryptoCore::b64_encode_str(hash.ptr(), hash.size()); - -		PackedByteArray rq_blob = mh.get_requirements(); -		String req_string; -		if (rq_blob.size() > 8) { -			CodeSignRequirements rq = CodeSignRequirements(rq_blob); -			Vector<String> rqs = rq.parse_requirements(); -			for (int j = 0; j < rqs.size(); j++) { -				if (rqs[j].begins_with("designated => ")) { -					req_string = rqs[j].replace("designated => ", ""); -				} -			} -		} -		if (req_string.is_empty()) { -			req_string = "cdhash H\"" + String::hex_encode_buffer(hash.ptr(), hash.size()) + "\""; -		} -		print_verbose(vformat("CodeSign/CodeResources: Nested object %s (cputype: %d) cdhash:%s designated rq:%s", f.name, mh.get_cputype(), f.hash, req_string)); -		if (f.requirements != req_string) { -			if (i != 0) { -				f.requirements += " or "; -			} -			f.requirements += req_string; -		} -	} -	files2.push_back(f); - -	CLEANUP(); -	return true; - -#undef CLEANUP -} - -bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const String &p_path, const String &p_main_exe_path) { -	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); -	ERR_FAIL_COND_V(da.is_null(), false); -	Error err = da->change_dir(p_root.plus_file(p_path)); -	ERR_FAIL_COND_V(err != OK, false); - -	bool ret = true; -	da->list_dir_begin(); -	String n = da->get_next(); -	while (n != String()) { -		if (n != "." && n != "..") { -			String path = p_root.plus_file(p_path).plus_file(n); -			if (path == p_main_exe_path) { -				n = da->get_next(); -				continue; // Skip main executable. -			} -			if (da->current_is_dir()) { -				CRMatch found = match_rules2(p_path.plus_file(n)); -				String fmw_ver = "Current"; // Framework version (default). -				String info_path; -				String main_exe; -				bool bundle = false; -				if (da->file_exists(path.plus_file("Contents/Info.plist"))) { -					info_path = path.plus_file("Contents/Info.plist"); -					main_exe = path.plus_file("Contents/MacOS"); -					bundle = true; -				} else if (da->file_exists(path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) { -					info_path = path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)); -					main_exe = path.plus_file(vformat("Versions/%s", fmw_ver)); -					bundle = true; -				} else if (da->file_exists(path.plus_file("Info.plist"))) { -					info_path = path.plus_file("Info.plist"); -					main_exe = path; -					bundle = true; -				} -				if (bundle && found == CRMatch::CR_MATCH_NESTED && !info_path.is_empty()) { -					// Read Info.plist. -					PList info_plist; -					if (info_plist.load_file(info_path)) { -						if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleExecutable")) { -							main_exe = main_exe.plus_file(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data())); -						} else { -							ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid Info.plist, no exe name."); -						} -					} else { -						ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid Info.plist, can't load."); -					} -					ret = ret && add_nested_file(p_root, p_path.plus_file(n), main_exe); -				} else { -					ret = ret && add_folder_recursive(p_root, p_path.plus_file(n), p_main_exe_path); -				} -			} else { -				ret = ret && add_file1(p_root, p_path.plus_file(n)); -				ret = ret && add_file2(p_root, p_path.plus_file(n)); -			} -		} - -		n = da->get_next(); -	} - -	da->list_dir_end(); -	return ret; -} - -bool CodeSignCodeResources::save_to_file(const String &p_path) { -	PList pl; - -	print_verbose(vformat("CodeSign/CodeResources: Writing to file: %s", p_path)); - -	// Write version 1 hashes. -	Ref<PListNode> files1_dict = PListNode::new_dict(); -	pl.get_root()->push_subnode(files1_dict, "files"); -	for (int i = 0; i < files1.size(); i++) { -		if (files1[i].optional) { -			Ref<PListNode> file_dict = PListNode::new_dict(); -			files1_dict->push_subnode(file_dict, files1[i].name); - -			file_dict->push_subnode(PListNode::new_data(files1[i].hash), "hash"); -			file_dict->push_subnode(PListNode::new_bool(true), "optional"); -		} else { -			files1_dict->push_subnode(PListNode::new_data(files1[i].hash), files1[i].name); -		} -	} - -	// Write version 2 hashes. -	Ref<PListNode> files2_dict = PListNode::new_dict(); -	pl.get_root()->push_subnode(files2_dict, "files2"); -	for (int i = 0; i < files2.size(); i++) { -		Ref<PListNode> file_dict = PListNode::new_dict(); -		files2_dict->push_subnode(file_dict, files2[i].name); - -		if (files2[i].nested) { -			file_dict->push_subnode(PListNode::new_data(files2[i].hash), "cdhash"); -			file_dict->push_subnode(PListNode::new_string(files2[i].requirements), "requirement"); -		} else { -			file_dict->push_subnode(PListNode::new_data(files2[i].hash), "hash"); -			file_dict->push_subnode(PListNode::new_data(files2[i].hash2), "hash2"); -			if (files2[i].optional) { -				file_dict->push_subnode(PListNode::new_bool(true), "optional"); -			} -		} -	} - -	// Write version 1 rules. -	Ref<PListNode> rules1_dict = PListNode::new_dict(); -	pl.get_root()->push_subnode(rules1_dict, "rules"); -	for (int i = 0; i < rules1.size(); i++) { -		if (rules1[i].store) { -			if (rules1[i].key.is_empty() && rules1[i].weight <= 0) { -				rules1_dict->push_subnode(PListNode::new_bool(true), rules1[i].file_pattern); -			} else { -				Ref<PListNode> rule_dict = PListNode::new_dict(); -				rules1_dict->push_subnode(rule_dict, rules1[i].file_pattern); -				if (!rules1[i].key.is_empty()) { -					rule_dict->push_subnode(PListNode::new_bool(true), rules1[i].key); -				} -				if (rules1[i].weight != 1) { -					rule_dict->push_subnode(PListNode::new_real(rules1[i].weight), "weight"); -				} -			} -		} -	} - -	// Write version 2 rules. -	Ref<PListNode> rules2_dict = PListNode::new_dict(); -	pl.get_root()->push_subnode(rules2_dict, "rules2"); -	for (int i = 0; i < rules2.size(); i++) { -		if (rules2[i].store) { -			if (rules2[i].key.is_empty() && rules2[i].weight <= 0) { -				rules2_dict->push_subnode(PListNode::new_bool(true), rules2[i].file_pattern); -			} else { -				Ref<PListNode> rule_dict = PListNode::new_dict(); -				rules2_dict->push_subnode(rule_dict, rules2[i].file_pattern); -				if (!rules2[i].key.is_empty()) { -					rule_dict->push_subnode(PListNode::new_bool(true), rules2[i].key); -				} -				if (rules2[i].weight != 1) { -					rule_dict->push_subnode(PListNode::new_real(rules2[i].weight), "weight"); -				} -			} -		} -	} -	String text = pl.save_text(); -	ERR_FAIL_COND_V_MSG(text.is_empty(), false, "CodeSign/CodeResources: Generating resources PList failed."); - -	Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE); -	ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); - -	CharString cs = text.utf8(); -	fa->store_buffer((const uint8_t *)cs.ptr(), cs.length()); -	return true; -} - -/*************************************************************************/ -/* CodeSignRequirements                                                  */ -/*************************************************************************/ - -CodeSignRequirements::CodeSignRequirements() { -	blob.append_array({ 0xFA, 0xDE, 0x0C, 0x01 }); // Requirement set magic. -	blob.append_array({ 0x00, 0x00, 0x00, 0x0C }); // Length of requirements set (12 bytes). -	blob.append_array({ 0x00, 0x00, 0x00, 0x00 }); // Empty. -} - -CodeSignRequirements::CodeSignRequirements(const PackedByteArray &p_data) { -	blob = p_data; -} - -_FORCE_INLINE_ void CodeSignRequirements::_parse_certificate_slot(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const { -#define _R(x) BSWAP32(*(uint32_t *)(blob.ptr() + x)) -	ERR_FAIL_COND_MSG(r_pos >= p_rq_size, "CodeSign/Requirements: Out of bounds."); -	r_out += "certificate "; -	uint32_t tag_slot = _R(r_pos); -	if (tag_slot == 0x00000000) { -		r_out += "leaf"; -	} else if (tag_slot == 0xffffffff) { -		r_out += "root"; -	} else { -		r_out += itos((int32_t)tag_slot); -	} -	r_pos += 4; -#undef _R -} - -_FORCE_INLINE_ void CodeSignRequirements::_parse_key(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const { -#define _R(x) BSWAP32(*(uint32_t *)(blob.ptr() + x)) -	ERR_FAIL_COND_MSG(r_pos >= p_rq_size, "CodeSign/Requirements: Out of bounds."); -	uint32_t key_size = _R(r_pos); -	ERR_FAIL_COND_MSG(r_pos + key_size > p_rq_size, "CodeSign/Requirements: Out of bounds."); -	CharString key; -	key.resize(key_size); -	memcpy(key.ptrw(), blob.ptr() + r_pos + 4, key_size); -	r_pos += 4 + key_size + PAD(key_size, 4); -	r_out += "[" + String::utf8(key, key_size) + "]"; -#undef _R -} - -_FORCE_INLINE_ void CodeSignRequirements::_parse_oid_key(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const { -#define _R(x) BSWAP32(*(uint32_t *)(blob.ptr() + x)) -	ERR_FAIL_COND_MSG(r_pos >= p_rq_size, "CodeSign/Requirements: Out of bounds."); -	uint32_t key_size = _R(r_pos); -	ERR_FAIL_COND_MSG(r_pos + key_size > p_rq_size, "CodeSign/Requirements: Out of bounds."); -	r_out += "[field."; -	r_out += itos(blob[r_pos + 4] / 40) + "."; -	r_out += itos(blob[r_pos + 4] % 40); -	uint32_t spos = r_pos + 5; -	while (spos < r_pos + 4 + key_size) { -		r_out += "."; -		if (blob[spos] <= 127) { -			r_out += itos(blob[spos]); -			spos += 1; -		} else { -			uint32_t x = (0x7F & blob[spos]) << 7; -			spos += 1; -			while (blob[spos] > 127) { -				x = (x + (0x7F & blob[spos])) << 7; -				spos += 1; -			} -			x = (x + (0x7F & blob[spos])); -			r_out += itos(x); -			spos += 1; -		} -	} -	r_out += "]"; -	r_pos += 4 + key_size + PAD(key_size, 4); -#undef _R -} - -_FORCE_INLINE_ void CodeSignRequirements::_parse_hash_string(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const { -#define _R(x) BSWAP32(*(uint32_t *)(blob.ptr() + x)) -	ERR_FAIL_COND_MSG(r_pos >= p_rq_size, "CodeSign/Requirements: Out of bounds."); -	uint32_t tag_size = _R(r_pos); -	ERR_FAIL_COND_MSG(r_pos + tag_size > p_rq_size, "CodeSign/Requirements: Out of bounds."); -	PackedByteArray data; -	data.resize(tag_size); -	memcpy(data.ptrw(), blob.ptr() + r_pos + 4, tag_size); -	r_out += "H\"" + String::hex_encode_buffer(data.ptr(), data.size()) + "\""; -	r_pos += 4 + tag_size + PAD(tag_size, 4); -#undef _R -} - -_FORCE_INLINE_ void CodeSignRequirements::_parse_value(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const { -#define _R(x) BSWAP32(*(uint32_t *)(blob.ptr() + x)) -	ERR_FAIL_COND_MSG(r_pos >= p_rq_size, "CodeSign/Requirements: Out of bounds."); -	uint32_t key_size = _R(r_pos); -	ERR_FAIL_COND_MSG(r_pos + key_size > p_rq_size, "CodeSign/Requirements: Out of bounds."); -	CharString key; -	key.resize(key_size); -	memcpy(key.ptrw(), blob.ptr() + r_pos + 4, key_size); -	r_pos += 4 + key_size + PAD(key_size, 4); -	r_out += "\"" + String::utf8(key, key_size) + "\""; -#undef _R -} - -_FORCE_INLINE_ void CodeSignRequirements::_parse_date(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const { -#define _R(x) BSWAP32(*(uint32_t *)(blob.ptr() + x)) -	ERR_FAIL_COND_MSG(r_pos >= p_rq_size, "CodeSign/Requirements: Out of bounds."); -	uint32_t date = _R(r_pos); -	time_t t = 978307200 + date; -	struct tm lt; -#ifdef WINDOWS_ENABLED -	gmtime_s(<, &t); -#else -	gmtime_r(&t, <); -#endif -	r_out += vformat("<%04d-%02d-%02d ", (int)(1900 + lt.tm_year), (int)(lt.tm_mon + 1), (int)(lt.tm_mday)) + vformat("%02d:%02d:%02d +0000>", (int)(lt.tm_hour), (int)(lt.tm_min), (int)(lt.tm_sec)); -#undef _R -} - -_FORCE_INLINE_ bool CodeSignRequirements::_parse_match(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const { -#define _R(x) BSWAP32(*(uint32_t *)(blob.ptr() + x)) -	ERR_FAIL_COND_V_MSG(r_pos >= p_rq_size, false, "CodeSign/Requirements: Out of bounds."); -	uint32_t match = _R(r_pos); -	r_pos += 4; -	switch (match) { -		case 0x00000000: { -			r_out += "exists"; -		} break; -		case 0x00000001: { -			r_out += "= "; -			_parse_value(r_pos, r_out, p_rq_size); -		} break; -		case 0x00000002: { -			r_out += "~ "; -			_parse_value(r_pos, r_out, p_rq_size); -		} break; -		case 0x00000003: { -			r_out += "= *"; -			_parse_value(r_pos, r_out, p_rq_size); -		} break; -		case 0x00000004: { -			r_out += "= "; -			_parse_value(r_pos, r_out, p_rq_size); -			r_out += "*"; -		} break; -		case 0x00000005: { -			r_out += "< "; -			_parse_value(r_pos, r_out, p_rq_size); -		} break; -		case 0x00000006: { -			r_out += "> "; -			_parse_value(r_pos, r_out, p_rq_size); -		} break; -		case 0x00000007: { -			r_out += "<= "; -			_parse_value(r_pos, r_out, p_rq_size); -		} break; -		case 0x00000008: { -			r_out += ">= "; -			_parse_value(r_pos, r_out, p_rq_size); -		} break; -		case 0x00000009: { -			r_out += "= "; -			_parse_date(r_pos, r_out, p_rq_size); -		} break; -		case 0x0000000A: { -			r_out += "< "; -			_parse_date(r_pos, r_out, p_rq_size); -		} break; -		case 0x0000000B: { -			r_out += "> "; -			_parse_date(r_pos, r_out, p_rq_size); -		} break; -		case 0x0000000C: { -			r_out += "<= "; -			_parse_date(r_pos, r_out, p_rq_size); -		} break; -		case 0x0000000D: { -			r_out += ">= "; -			_parse_date(r_pos, r_out, p_rq_size); -		} break; -		case 0x0000000E: { -			r_out += "absent"; -		} break; -		default: { -			return false; -		} -	} -	return true; -#undef _R -} - -Vector<String> CodeSignRequirements::parse_requirements() const { -#define _R(x) BSWAP32(*(uint32_t *)(blob.ptr() + x)) -	Vector<String> list; - -	// Read requirements set header. -	ERR_FAIL_COND_V_MSG(blob.size() < 12, list, "CodeSign/Requirements: Blob is too small."); -	uint32_t magic = _R(0); -	ERR_FAIL_COND_V_MSG(magic != 0xfade0c01, list, "CodeSign/Requirements: Invalid set magic."); -	uint32_t size = _R(4); -	ERR_FAIL_COND_V_MSG(size != (uint32_t)blob.size(), list, "CodeSign/Requirements: Invalid set size."); -	uint32_t count = _R(8); - -	for (uint32_t i = 0; i < count; i++) { -		String out; - -		// Read requirement header. -		uint32_t rq_type = _R(12 + i * 8); -		uint32_t rq_offset = _R(12 + i * 8 + 4); -		ERR_FAIL_COND_V_MSG(rq_offset + 12 >= (uint32_t)blob.size(), list, "CodeSign/Requirements: Invalid requirement offset."); -		switch (rq_type) { -			case 0x00000001: { -				out += "host => "; -			} break; -			case 0x00000002: { -				out += "guest => "; -			} break; -			case 0x00000003: { -				out += "designated => "; -			} break; -			case 0x00000004: { -				out += "library => "; -			} break; -			case 0x00000005: { -				out += "plugin => "; -			} break; -			default: { -				ERR_FAIL_V_MSG(list, "CodeSign/Requirements: Invalid requirement type."); -			} -		} -		uint32_t rq_magic = _R(rq_offset); -		uint32_t rq_size = _R(rq_offset + 4); -		uint32_t rq_ver = _R(rq_offset + 8); -		uint32_t pos = rq_offset + 12; -		ERR_FAIL_COND_V_MSG(rq_magic != 0xfade0c00, list, "CodeSign/Requirements: Invalid requirement magic."); -		ERR_FAIL_COND_V_MSG(rq_ver != 0x00000001, list, "CodeSign/Requirements: Invalid requirement version."); - -		// Read requirement tokens. -		List<String> tokens; -		while (pos < rq_offset + rq_size) { -			uint32_t rq_tag = _R(pos); -			pos += 4; -			String token; -			switch (rq_tag) { -				case 0x00000000: { -					token = "false"; -				} break; -				case 0x00000001: { -					token = "true"; -				} break; -				case 0x00000002: { -					token = "identifier "; -					_parse_value(pos, token, rq_offset + rq_size); -				} break; -				case 0x00000003: { -					token = "anchor apple"; -				} break; -				case 0x00000004: { -					_parse_certificate_slot(pos, token, rq_offset + rq_size); -					token += " "; -					_parse_hash_string(pos, token, rq_offset + rq_size); -				} break; -				case 0x00000005: { -					token = "info"; -					_parse_key(pos, token, rq_offset + rq_size); -					token += " = "; -					_parse_value(pos, token, rq_offset + rq_size); -				} break; -				case 0x00000006: { -					token = "and"; -				} break; -				case 0x00000007: { -					token = "or"; -				} break; -				case 0x00000008: { -					token = "cdhash "; -					_parse_hash_string(pos, token, rq_offset + rq_size); -				} break; -				case 0x00000009: { -					token = "!"; -				} break; -				case 0x0000000A: { -					token = "info"; -					_parse_key(pos, token, rq_offset + rq_size); -					token += " "; -					ERR_FAIL_COND_V_MSG(!_parse_match(pos, token, rq_offset + rq_size), list, "CodeSign/Requirements: Unsupported match suffix."); -				} break; -				case 0x0000000B: { -					_parse_certificate_slot(pos, token, rq_offset + rq_size); -					_parse_key(pos, token, rq_offset + rq_size); -					token += " "; -					ERR_FAIL_COND_V_MSG(!_parse_match(pos, token, rq_offset + rq_size), list, "CodeSign/Requirements: Unsupported match suffix."); -				} break; -				case 0x0000000C: { -					_parse_certificate_slot(pos, token, rq_offset + rq_size); -					token += " trusted"; -				} break; -				case 0x0000000D: { -					token = "anchor trusted"; -				} break; -				case 0x0000000E: { -					_parse_certificate_slot(pos, token, rq_offset + rq_size); -					_parse_oid_key(pos, token, rq_offset + rq_size); -					token += " "; -					ERR_FAIL_COND_V_MSG(!_parse_match(pos, token, rq_offset + rq_size), list, "CodeSign/Requirements: Unsupported match suffix."); -				} break; -				case 0x0000000F: { -					token = "anchor apple generic"; -				} break; -				default: { -					ERR_FAIL_V_MSG(list, "CodeSign/Requirements: Invalid requirement token."); -				} break; -			} -			tokens.push_back(token); -		} - -		// Polish to infix notation (w/o bracket optimization). -		for (List<String>::Element *E = tokens.back(); E; E = E->prev()) { -			if (E->get() == "and") { -				ERR_FAIL_COND_V_MSG(!E->next() || !E->next()->next(), list, "CodeSign/Requirements: Invalid token sequence."); -				String token = "(" + E->next()->get() + " and " + E->next()->next()->get() + ")"; -				tokens.erase(E->next()->next()); -				tokens.erase(E->next()); -				E->get() = token; -			} else if (E->get() == "or") { -				ERR_FAIL_COND_V_MSG(!E->next() || !E->next()->next(), list, "CodeSign/Requirements: Invalid token sequence."); -				String token = "(" + E->next()->get() + " or " + E->next()->next()->get() + ")"; -				tokens.erase(E->next()->next()); -				tokens.erase(E->next()); -				E->get() = token; -			} -		} - -		if (tokens.size() == 1) { -			list.push_back(out + tokens.front()->get()); -		} else { -			ERR_FAIL_V_MSG(list, "CodeSign/Requirements: Invalid token sequence."); -		} -	} - -	return list; -#undef _R -} - -PackedByteArray CodeSignRequirements::get_hash_sha1() const { -	PackedByteArray hash; -	hash.resize(0x14); - -	CryptoCore::SHA1Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -PackedByteArray CodeSignRequirements::get_hash_sha256() const { -	PackedByteArray hash; -	hash.resize(0x20); - -	CryptoCore::SHA256Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -int CodeSignRequirements::get_size() const { -	return blob.size(); -} - -void CodeSignRequirements::write_to_file(Ref<FileAccess> p_file) const { -	ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/Requirements: Invalid file handle."); -	p_file->store_buffer(blob.ptr(), blob.size()); -} - -/*************************************************************************/ -/* CodeSignEntitlementsText                                             */ -/*************************************************************************/ - -CodeSignEntitlementsText::CodeSignEntitlementsText() { -	blob.append_array({ 0xFA, 0xDE, 0x71, 0x71 }); // Text Entitlements set magic. -	blob.append_array({ 0x00, 0x00, 0x00, 0x08 }); // Length (8 bytes). -} - -CodeSignEntitlementsText::CodeSignEntitlementsText(const String &p_string) { -	CharString utf8 = p_string.utf8(); -	blob.append_array({ 0xFA, 0xDE, 0x71, 0x71 }); // Text Entitlements set magic. -	for (int i = 3; i >= 0; i--) { -		uint8_t x = ((utf8.length() + 8) >> i * 8) & 0xFF; // Size. -		blob.push_back(x); -	} -	for (int i = 0; i < utf8.length(); i++) { // Write data. -		blob.push_back(utf8[i]); -	} -} - -PackedByteArray CodeSignEntitlementsText::get_hash_sha1() const { -	PackedByteArray hash; -	hash.resize(0x14); - -	CryptoCore::SHA1Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -PackedByteArray CodeSignEntitlementsText::get_hash_sha256() const { -	PackedByteArray hash; -	hash.resize(0x20); - -	CryptoCore::SHA256Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -int CodeSignEntitlementsText::get_size() const { -	return blob.size(); -} - -void CodeSignEntitlementsText::write_to_file(Ref<FileAccess> p_file) const { -	ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/EntitlementsText: Invalid file handle."); -	p_file->store_buffer(blob.ptr(), blob.size()); -} - -/*************************************************************************/ -/* CodeSignEntitlementsBinary                                           */ -/*************************************************************************/ - -CodeSignEntitlementsBinary::CodeSignEntitlementsBinary() { -	blob.append_array({ 0xFA, 0xDE, 0x71, 0x72 }); // Binary Entitlements magic. -	blob.append_array({ 0x00, 0x00, 0x00, 0x08 }); // Length (8 bytes). -} - -CodeSignEntitlementsBinary::CodeSignEntitlementsBinary(const String &p_string) { -	PList pl = PList(p_string); - -	PackedByteArray asn1 = pl.save_asn1(); -	blob.append_array({ 0xFA, 0xDE, 0x71, 0x72 }); // Binary Entitlements magic. -	uint32_t size = asn1.size() + 8; -	for (int i = 3; i >= 0; i--) { -		uint8_t x = (size >> i * 8) & 0xFF; // Size. -		blob.push_back(x); -	} -	blob.append_array(asn1); // Write data. -} - -PackedByteArray CodeSignEntitlementsBinary::get_hash_sha1() const { -	PackedByteArray hash; -	hash.resize(0x14); - -	CryptoCore::SHA1Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -PackedByteArray CodeSignEntitlementsBinary::get_hash_sha256() const { -	PackedByteArray hash; -	hash.resize(0x20); - -	CryptoCore::SHA256Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -int CodeSignEntitlementsBinary::get_size() const { -	return blob.size(); -} - -void CodeSignEntitlementsBinary::write_to_file(Ref<FileAccess> p_file) const { -	ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/EntitlementsBinary: Invalid file handle."); -	p_file->store_buffer(blob.ptr(), blob.size()); -} - -/*************************************************************************/ -/* CodeSignCodeDirectory                                                 */ -/*************************************************************************/ - -CodeSignCodeDirectory::CodeSignCodeDirectory() { -	blob.append_array({ 0xFA, 0xDE, 0x0C, 0x02 }); // Code Directory magic. -	blob.append_array({ 0x00, 0x00, 0x00, 0x00 }); // Size (8 bytes). -} - -CodeSignCodeDirectory::CodeSignCodeDirectory(uint8_t p_hash_size, uint8_t p_hash_type, bool p_main, const CharString &p_id, const CharString &p_team_id, uint32_t p_page_size, uint64_t p_exe_limit, uint64_t p_code_limit) { -	pages = p_code_limit / (uint64_t(1) << p_page_size); -	remain = p_code_limit % (uint64_t(1) << p_page_size); -	code_slots = pages + (remain > 0 ? 1 : 0); -	special_slots = 7; - -	int cd_size = 8 + sizeof(CodeDirectoryHeader) + (code_slots + special_slots) * p_hash_size + p_id.size() + p_team_id.size(); -	int cd_off = 8 + sizeof(CodeDirectoryHeader); -	blob.append_array({ 0xFA, 0xDE, 0x0C, 0x02 }); // Code Directory magic. -	for (int i = 3; i >= 0; i--) { -		uint8_t x = (cd_size >> i * 8) & 0xFF; // Size. -		blob.push_back(x); -	} -	blob.resize(cd_size); -	memset(blob.ptrw() + 8, 0x00, cd_size - 8); -	CodeDirectoryHeader *cd = reinterpret_cast<CodeDirectoryHeader *>(blob.ptrw() + 8); - -	bool is_64_cl = (p_code_limit >= std::numeric_limits<uint32_t>::max()); - -	// Version and options. -	cd->version = BSWAP32(0x20500); -	cd->flags = BSWAP32(SIGNATURE_ADHOC | SIGNATURE_RUNTIME); -	cd->special_slots = BSWAP32(special_slots); -	cd->code_slots = BSWAP32(code_slots); -	if (is_64_cl) { -		cd->code_limit_64 = BSWAP64(p_code_limit); -	} else { -		cd->code_limit = BSWAP32(p_code_limit); -	} -	cd->hash_size = p_hash_size; -	cd->hash_type = p_hash_type; -	cd->page_size = p_page_size; -	cd->exec_seg_base = 0x00; -	cd->exec_seg_limit = BSWAP64(p_exe_limit); -	cd->exec_seg_flags = 0; -	if (p_main) { -		cd->exec_seg_flags |= EXECSEG_MAIN_BINARY; -	} -	cd->exec_seg_flags = BSWAP64(cd->exec_seg_flags); -	uint32_t version = (11 << 16) + (3 << 8) + 0; // Version 11.3.0 -	cd->runtime = BSWAP32(version); - -	// Copy ID. -	cd->ident_offset = BSWAP32(cd_off); -	memcpy(blob.ptrw() + cd_off, p_id.get_data(), p_id.size()); -	cd_off += p_id.size(); - -	// Copy Team ID. -	if (p_team_id.length() > 0) { -		cd->team_offset = BSWAP32(cd_off); -		memcpy(blob.ptrw() + cd_off, p_team_id.get_data(), p_team_id.size()); -		cd_off += p_team_id.size(); -	} else { -		cd->team_offset = 0; -	} - -	// Scatter vector. -	cd->scatter_vector_offset = 0; // Not used. - -	// Executable hashes offset. -	cd->hash_offset = BSWAP32(cd_off + special_slots * cd->hash_size); -} - -bool CodeSignCodeDirectory::set_hash_in_slot(const PackedByteArray &p_hash, int p_slot) { -	ERR_FAIL_COND_V_MSG((p_slot < -special_slots) || (p_slot >= code_slots), false, vformat("CodeSign/CodeDirectory: Invalid hash slot index: %d.", p_slot)); -	CodeDirectoryHeader *cd = reinterpret_cast<CodeDirectoryHeader *>(blob.ptrw() + 8); -	for (int i = 0; i < cd->hash_size; i++) { -		blob.write[BSWAP32(cd->hash_offset) + p_slot * cd->hash_size + i] = p_hash[i]; -	} -	return true; -} - -int32_t CodeSignCodeDirectory::get_page_count() { -	return pages; -} - -int32_t CodeSignCodeDirectory::get_page_remainder() { -	return remain; -} - -PackedByteArray CodeSignCodeDirectory::get_hash_sha1() const { -	PackedByteArray hash; -	hash.resize(0x14); - -	CryptoCore::SHA1Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -PackedByteArray CodeSignCodeDirectory::get_hash_sha256() const { -	PackedByteArray hash; -	hash.resize(0x20); - -	CryptoCore::SHA256Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -int CodeSignCodeDirectory::get_size() const { -	return blob.size(); -} - -void CodeSignCodeDirectory::write_to_file(Ref<FileAccess> p_file) const { -	ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/CodeDirectory: Invalid file handle."); -	p_file->store_buffer(blob.ptr(), blob.size()); -} - -/*************************************************************************/ -/* CodeSignSignature                                                     */ -/*************************************************************************/ - -CodeSignSignature::CodeSignSignature() { -	blob.append_array({ 0xFA, 0xDE, 0x0B, 0x01 }); // Signature magic. -	uint32_t sign_size = 8; // Ad-hoc signature is empty. -	for (int i = 3; i >= 0; i--) { -		uint8_t x = (sign_size >> i * 8) & 0xFF; // Size. -		blob.push_back(x); -	} -} - -PackedByteArray CodeSignSignature::get_hash_sha1() const { -	PackedByteArray hash; -	hash.resize(0x14); - -	CryptoCore::SHA1Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -PackedByteArray CodeSignSignature::get_hash_sha256() const { -	PackedByteArray hash; -	hash.resize(0x20); - -	CryptoCore::SHA256Context ctx; -	ctx.start(); -	ctx.update(blob.ptr(), blob.size()); -	ctx.finish(hash.ptrw()); - -	return hash; -} - -int CodeSignSignature::get_size() const { -	return blob.size(); -} - -void CodeSignSignature::write_to_file(Ref<FileAccess> p_file) const { -	ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/Signature: Invalid file handle."); -	p_file->store_buffer(blob.ptr(), blob.size()); -} - -/*************************************************************************/ -/* CodeSignSuperBlob                                                     */ -/*************************************************************************/ - -bool CodeSignSuperBlob::add_blob(const Ref<CodeSignBlob> &p_blob) { -	if (p_blob.is_valid()) { -		blobs.push_back(p_blob); -		return true; -	} else { -		return false; -	} -} - -int CodeSignSuperBlob::get_size() const { -	int size = 12 + blobs.size() * 8; -	for (int i = 0; i < blobs.size(); i++) { -		if (blobs[i].is_null()) { -			return 0; -		} -		size += blobs[i]->get_size(); -	} -	return size; -} - -void CodeSignSuperBlob::write_to_file(Ref<FileAccess> p_file) const { -	ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/SuperBlob: Invalid file handle."); -	uint32_t size = get_size(); -	uint32_t data_offset = 12 + blobs.size() * 8; - -	// Write header. -	p_file->store_32(BSWAP32(0xfade0cc0)); -	p_file->store_32(BSWAP32(size)); -	p_file->store_32(BSWAP32(blobs.size())); - -	// Write index. -	for (int i = 0; i < blobs.size(); i++) { -		if (blobs[i].is_null()) { -			return; -		} -		p_file->store_32(BSWAP32(blobs[i]->get_index_type())); -		p_file->store_32(BSWAP32(data_offset)); -		data_offset += blobs[i]->get_size(); -	} - -	// Write blobs. -	for (int i = 0; i < blobs.size(); i++) { -		blobs[i]->write_to_file(p_file); -	} -} - -/*************************************************************************/ -/* CodeSign                                                              */ -/*************************************************************************/ - -PackedByteArray CodeSign::file_hash_sha1(const String &p_path) { -	PackedByteArray file_hash; -	Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); -	ERR_FAIL_COND_V_MSG(f.is_null(), PackedByteArray(), vformat("CodeSign: Can't open file: \"%s\".", p_path)); - -	CryptoCore::SHA1Context ctx; -	ctx.start(); - -	unsigned char step[4096]; -	while (true) { -		uint64_t br = f->get_buffer(step, 4096); -		if (br > 0) { -			ctx.update(step, br); -		} -		if (br < 4096) { -			break; -		} -	} - -	file_hash.resize(0x14); -	ctx.finish(file_hash.ptrw()); -	return file_hash; -} - -PackedByteArray CodeSign::file_hash_sha256(const String &p_path) { -	PackedByteArray file_hash; -	Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); -	ERR_FAIL_COND_V_MSG(f.is_null(), PackedByteArray(), vformat("CodeSign: Can't open file: \"%s\".", p_path)); - -	CryptoCore::SHA256Context ctx; -	ctx.start(); - -	unsigned char step[4096]; -	while (true) { -		uint64_t br = f->get_buffer(step, 4096); -		if (br > 0) { -			ctx.update(step, br); -		} -		if (br < 4096) { -			break; -		} -	} - -	file_hash.resize(0x20); -	ctx.finish(file_hash.ptrw()); -	return file_hash; -} - -Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const String &p_info, const String &p_exe_path, const String &p_bundle_path, const String &p_ent_path, bool p_ios_bundle, String &r_error_msg) { -#define CLEANUP()                                        \ -	if (files_to_sign.size() > 1) {                      \ -		for (int j = 0; j < files_to_sign.size(); j++) { \ -			da->remove(files_to_sign[j]);                \ -		}                                                \ -	} - -	print_verbose(vformat("CodeSign: Signing executable: %s, bundle: %s with entitlements %s", p_exe_path, p_bundle_path, p_ent_path)); - -	PackedByteArray info_hash1, info_hash2; -	PackedByteArray res_hash1, res_hash2; -	String id; -	String main_exe = p_exe_path; - -	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); -	if (da.is_null()) { -		r_error_msg = TTR("Can't get filesystem access."); -		ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CodeSign: Can't get filesystem access."); -	} - -	// Read Info.plist. -	if (!p_info.is_empty()) { -		print_verbose(vformat("CodeSign: Reading bundle info...")); -		PList info_plist; -		if (info_plist.load_file(p_info)) { -			info_hash1 = file_hash_sha1(p_info); -			info_hash2 = file_hash_sha256(p_info); -			if (info_hash1.is_empty() || info_hash2.is_empty()) { -				r_error_msg = TTR("Failed to get Info.plist hash."); -				ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to get Info.plist hash."); -			} - -			if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleExecutable")) { -				main_exe = p_exe_path.plus_file(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data())); -			} else { -				r_error_msg = TTR("Invalid Info.plist, no exe name."); -				ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid Info.plist, no exe name."); -			} - -			if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleIdentifier")) { -				id = info_plist.get_root()->data_dict["CFBundleIdentifier"]->data_string.get_data(); -			} else { -				r_error_msg = TTR("Invalid Info.plist, no bundle id."); -				ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid Info.plist, no bundle id."); -			} -		} else { -			r_error_msg = TTR("Invalid Info.plist, can't load."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid Info.plist, can't load."); -		} -	} - -	// Extract fat binary. -	Vector<String> files_to_sign; -	if (LipO::is_lipo(main_exe)) { -		print_verbose(vformat("CodeSign: Executable is fat, extracting...")); -		String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo"); -		Error err = da->make_dir_recursive(tmp_path_name); -		if (err != OK) { -			r_error_msg = vformat(TTR("Failed to create \"%s\" subfolder."), tmp_path_name); -			ERR_FAIL_V_MSG(FAILED, vformat("CodeSign: Failed to create \"%s\" subfolder.", tmp_path_name)); -		} -		LipO lip; -		if (lip.open_file(main_exe)) { -			for (int i = 0; i < lip.get_arch_count(); i++) { -				if (!lip.extract_arch(i, tmp_path_name.plus_file("_exe_" + itos(i)))) { -					CLEANUP(); -					r_error_msg = TTR("Failed to extract thin binary."); -					ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to extract thin binary."); -				} -				files_to_sign.push_back(tmp_path_name.plus_file("_exe_" + itos(i))); -			} -		} -	} else if (MachO::is_macho(main_exe)) { -		print_verbose(vformat("CodeSign: Executable is thin...")); -		files_to_sign.push_back(main_exe); -	} else { -		r_error_msg = TTR("Invalid binary format."); -		ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid binary format."); -	} - -	// Check if it's already signed. -	if (!p_force) { -		for (int i = 0; i < files_to_sign.size(); i++) { -			MachO mh; -			mh.open_file(files_to_sign[i]); -			if (mh.is_signed()) { -				CLEANUP(); -				r_error_msg = TTR("Already signed!"); -				ERR_FAIL_V_MSG(FAILED, "CodeSign: Already signed!"); -			} -		} -	} - -	// Generate core resources. -	if (!p_bundle_path.is_empty()) { -		print_verbose(vformat("CodeSign: Generating bundle CodeResources...")); -		CodeSignCodeResources cr; - -		if (p_ios_bundle) { -			cr.add_rule1("^.*"); -			cr.add_rule1("^.*\\.lproj/", "optional", 100); -			cr.add_rule1("^.*\\.lproj/locversion.plist$", "omit", 1100); -			cr.add_rule1("^Base\\.lproj/", "", 1010); -			cr.add_rule1("^version.plist$"); - -			cr.add_rule2(".*\\.dSYM($|/)", "", 11); -			cr.add_rule2("^(.*/)?\\.DS_Store$", "omit", 2000); -			cr.add_rule2("^.*"); -			cr.add_rule2("^.*\\.lproj/", "optional", 1000); -			cr.add_rule2("^.*\\.lproj/locversion.plist$", "omit", 1100); -			cr.add_rule2("^Base\\.lproj/", "", 1010); -			cr.add_rule2("^Info\\.plist$", "omit", 20); -			cr.add_rule2("^PkgInfo$", "omit", 20); -			cr.add_rule2("^embedded\\.provisionprofile$", "", 10); -			cr.add_rule2("^version\\.plist$", "", 20); - -			cr.add_rule2("^_MASReceipt", "omit", 2000, false); -			cr.add_rule2("^_CodeSignature", "omit", 2000, false); -			cr.add_rule2("^CodeResources", "omit", 2000, false); -		} else { -			cr.add_rule1("^Resources/"); -			cr.add_rule1("^Resources/.*\\.lproj/", "optional", 1000); -			cr.add_rule1("^Resources/.*\\.lproj/locversion.plist$", "omit", 1100); -			cr.add_rule1("^Resources/Base\\.lproj/", "", 1010); -			cr.add_rule1("^version.plist$"); - -			cr.add_rule2(".*\\.dSYM($|/)", "", 11); -			cr.add_rule2("^(.*/)?\\.DS_Store$", "omit", 2000); -			cr.add_rule2("^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/", "nested", 10); -			cr.add_rule2("^.*"); -			cr.add_rule2("^Info\\.plist$", "omit", 20); -			cr.add_rule2("^PkgInfo$", "omit", 20); -			cr.add_rule2("^Resources/", "", 20); -			cr.add_rule2("^Resources/.*\\.lproj/", "optional", 1000); -			cr.add_rule2("^Resources/.*\\.lproj/locversion.plist$", "omit", 1100); -			cr.add_rule2("^Resources/Base\\.lproj/", "", 1010); -			cr.add_rule2("^[^/]+$", "nested", 10); -			cr.add_rule2("^embedded\\.provisionprofile$", "", 10); -			cr.add_rule2("^version\\.plist$", "", 20); -			cr.add_rule2("^_MASReceipt", "omit", 2000, false); -			cr.add_rule2("^_CodeSignature", "omit", 2000, false); -			cr.add_rule2("^CodeResources", "omit", 2000, false); -		} - -		if (!cr.add_folder_recursive(p_bundle_path, "", main_exe)) { -			CLEANUP(); -			r_error_msg = TTR("Failed to process nested resources."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to process nested resources."); -		} -		Error err = da->make_dir_recursive(p_bundle_path.plus_file("_CodeSignature")); -		if (err != OK) { -			CLEANUP(); -			r_error_msg = TTR("Failed to create _CodeSignature subfolder."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to create _CodeSignature subfolder."); -		} -		cr.save_to_file(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources")); -		res_hash1 = file_hash_sha1(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources")); -		res_hash2 = file_hash_sha256(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources")); -		if (res_hash1.is_empty() || res_hash2.is_empty()) { -			CLEANUP(); -			r_error_msg = TTR("Failed to get CodeResources hash."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to get CodeResources hash."); -		} -	} - -	// Generate common signature structures. -	if (id.is_empty()) { -		CryptoCore::RandomGenerator rng; -		ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator."); -		uint8_t uuid[16]; -		Error err = rng.get_random_bytes(uuid, 16); -		ERR_FAIL_COND_V_MSG(err, err, "Failed to generate UUID."); -		id = (String("a-55554944") /*a-UUID*/ + String::hex_encode_buffer(uuid, 16)); -	} -	CharString uuid_str = id.utf8(); -	print_verbose(vformat("CodeSign: Used bundle ID: %s", id)); - -	print_verbose(vformat("CodeSign: Processing entitlements...")); - -	Ref<CodeSignEntitlementsText> cet; -	Ref<CodeSignEntitlementsBinary> ceb; -	if (!p_ent_path.is_empty()) { -		String entitlements = FileAccess::get_file_as_string(p_ent_path); -		if (entitlements.is_empty()) { -			CLEANUP(); -			r_error_msg = TTR("Invalid entitlements file."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid entitlements file."); -		} -		cet = Ref<CodeSignEntitlementsText>(memnew(CodeSignEntitlementsText(entitlements))); -		ceb = Ref<CodeSignEntitlementsBinary>(memnew(CodeSignEntitlementsBinary(entitlements))); -	} - -	print_verbose(vformat("CodeSign: Generating requirements...")); -	Ref<CodeSignRequirements> rq; -	String team_id = ""; -	rq = Ref<CodeSignRequirements>(memnew(CodeSignRequirements())); - -	// Sign executables. -	for (int i = 0; i < files_to_sign.size(); i++) { -		MachO mh; -		if (!mh.open_file(files_to_sign[i])) { -			CLEANUP(); -			r_error_msg = TTR("Invalid executable file."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid executable file."); -		} -		print_verbose(vformat("CodeSign: Signing executable for cputype: %d ...", mh.get_cputype())); - -		print_verbose(vformat("CodeSign: Generating CodeDirectory...")); -		Ref<CodeSignCodeDirectory> cd1 = memnew(CodeSignCodeDirectory(0x14, 0x01, true, uuid_str, team_id.utf8(), 12, mh.get_exe_limit(), mh.get_code_limit())); -		Ref<CodeSignCodeDirectory> cd2 = memnew(CodeSignCodeDirectory(0x20, 0x02, true, uuid_str, team_id.utf8(), 12, mh.get_exe_limit(), mh.get_code_limit())); -		print_verbose(vformat("CodeSign: Calculating special slot hashes...")); -		if (info_hash2.size() == 0x20) { -			cd2->set_hash_in_slot(info_hash2, CodeSignCodeDirectory::SLOT_INFO_PLIST); -		} -		if (info_hash1.size() == 0x14) { -			cd1->set_hash_in_slot(info_hash1, CodeSignCodeDirectory::SLOT_INFO_PLIST); -		} -		cd1->set_hash_in_slot(rq->get_hash_sha1(), CodeSignCodeDirectory::Slot::SLOT_REQUIREMENTS); -		cd2->set_hash_in_slot(rq->get_hash_sha256(), CodeSignCodeDirectory::Slot::SLOT_REQUIREMENTS); -		if (res_hash2.size() == 0x20) { -			cd2->set_hash_in_slot(res_hash2, CodeSignCodeDirectory::SLOT_RESOURCES); -		} -		if (res_hash1.size() == 0x14) { -			cd1->set_hash_in_slot(res_hash1, CodeSignCodeDirectory::SLOT_RESOURCES); -		} -		if (cet.is_valid()) { -			cd1->set_hash_in_slot(cet->get_hash_sha1(), CodeSignCodeDirectory::Slot::SLOT_ENTITLEMENTS); //Text variant. -			cd2->set_hash_in_slot(cet->get_hash_sha256(), CodeSignCodeDirectory::Slot::SLOT_ENTITLEMENTS); -		} -		if (ceb.is_valid()) { -			cd1->set_hash_in_slot(ceb->get_hash_sha1(), CodeSignCodeDirectory::Slot::SLOT_DER_ENTITLEMENTS); //ASN.1 variant. -			cd2->set_hash_in_slot(ceb->get_hash_sha256(), CodeSignCodeDirectory::Slot::SLOT_DER_ENTITLEMENTS); -		} - -		// Calculate signature size. -		int sign_size = 12; // SuperBlob header. -		sign_size += cd1->get_size() + 8; -		sign_size += cd2->get_size() + 8; -		sign_size += rq->get_size() + 8; -		if (cet.is_valid()) { -			sign_size += cet->get_size() + 8; -		} -		if (ceb.is_valid()) { -			sign_size += ceb->get_size() + 8; -		} -		sign_size += 16; // Empty signature size. - -		// Alloc/resize signature load command. -		print_verbose(vformat("CodeSign: Reallocating space for the signature superblob (%d)...", sign_size)); -		if (!mh.set_signature_size(sign_size)) { -			CLEANUP(); -			r_error_msg = TTR("Can't resize signature load command."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Can't resize signature load command."); -		} - -		print_verbose(vformat("CodeSign: Calculating executable code hashes...")); -		// Calculate executable code hashes. -		PackedByteArray buffer; -		PackedByteArray hash1, hash2; -		hash1.resize(0x14); -		hash2.resize(0x20); -		buffer.resize(1 << 12); -		mh.get_file()->seek(0); -		for (int32_t j = 0; j < cd2->get_page_count(); j++) { -			mh.get_file()->get_buffer(buffer.ptrw(), (1 << 12)); -			CryptoCore::SHA256Context ctx2; -			ctx2.start(); -			ctx2.update(buffer.ptr(), (1 << 12)); -			ctx2.finish(hash2.ptrw()); -			cd2->set_hash_in_slot(hash2, j); - -			CryptoCore::SHA1Context ctx1; -			ctx1.start(); -			ctx1.update(buffer.ptr(), (1 << 12)); -			ctx1.finish(hash1.ptrw()); -			cd1->set_hash_in_slot(hash1, j); -		} -		if (cd2->get_page_remainder() > 0) { -			mh.get_file()->get_buffer(buffer.ptrw(), cd2->get_page_remainder()); -			CryptoCore::SHA256Context ctx2; -			ctx2.start(); -			ctx2.update(buffer.ptr(), cd2->get_page_remainder()); -			ctx2.finish(hash2.ptrw()); -			cd2->set_hash_in_slot(hash2, cd2->get_page_count()); - -			CryptoCore::SHA1Context ctx1; -			ctx1.start(); -			ctx1.update(buffer.ptr(), cd1->get_page_remainder()); -			ctx1.finish(hash1.ptrw()); -			cd1->set_hash_in_slot(hash1, cd1->get_page_count()); -		} - -		print_verbose(vformat("CodeSign: Generating signature...")); -		Ref<CodeSignSignature> cs; -		cs = Ref<CodeSignSignature>(memnew(CodeSignSignature())); - -		print_verbose(vformat("CodeSign: Writing signature superblob...")); -		// Write signature data to the executable. -		CodeSignSuperBlob sb = CodeSignSuperBlob(); -		sb.add_blob(cd2); -		sb.add_blob(cd1); -		sb.add_blob(rq); -		if (cet.is_valid()) { -			sb.add_blob(cet); -		} -		if (ceb.is_valid()) { -			sb.add_blob(ceb); -		} -		sb.add_blob(cs); -		mh.get_file()->seek(mh.get_signature_offset()); -		sb.write_to_file(mh.get_file()); -	} -	if (files_to_sign.size() > 1) { -		print_verbose(vformat("CodeSign: Rebuilding fat executable...")); -		LipO lip; -		if (!lip.create_file(main_exe, files_to_sign)) { -			CLEANUP(); -			r_error_msg = TTR("Failed to create fat binary."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to create fat binary."); -		} -		CLEANUP(); -	} -	FileAccess::set_unix_permissions(main_exe, 0755); // Restore unix permissions. -	return OK; -#undef CLEANUP -} - -Error CodeSign::codesign(bool p_use_hardened_runtime, bool p_force, const String &p_path, const String &p_ent_path, String &r_error_msg) { -	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); -	if (da.is_null()) { -		r_error_msg = TTR("Can't get filesystem access."); -		ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CodeSign: Can't get filesystem access."); -	} - -	if (da->dir_exists(p_path)) { -		String fmw_ver = "Current"; // Framework version (default). -		String info_path; -		String main_exe; -		String bundle_path; -		bool bundle = false; -		bool ios_bundle = false; -		if (da->file_exists(p_path.plus_file("Contents/Info.plist"))) { -			info_path = p_path.plus_file("Contents/Info.plist"); -			main_exe = p_path.plus_file("Contents/MacOS"); -			bundle_path = p_path.plus_file("Contents"); -			bundle = true; -		} else if (da->file_exists(p_path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) { -			info_path = p_path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)); -			main_exe = p_path.plus_file(vformat("Versions/%s", fmw_ver)); -			bundle_path = p_path.plus_file(vformat("Versions/%s", fmw_ver)); -			bundle = true; -		} else if (da->file_exists(p_path.plus_file("Info.plist"))) { -			info_path = p_path.plus_file("Info.plist"); -			main_exe = p_path; -			bundle_path = p_path; -			bundle = true; -			ios_bundle = true; -		} -		if (bundle) { -			return _codesign_file(p_use_hardened_runtime, p_force, info_path, main_exe, bundle_path, p_ent_path, ios_bundle, r_error_msg); -		} else { -			r_error_msg = TTR("Unknown bundle type."); -			ERR_FAIL_V_MSG(FAILED, "CodeSign: Unknown bundle type."); -		} -	} else if (da->file_exists(p_path)) { -		return _codesign_file(p_use_hardened_runtime, p_force, "", p_path, "", p_ent_path, false, r_error_msg); -	} else { -		r_error_msg = TTR("Unknown object type."); -		ERR_FAIL_V_MSG(FAILED, "CodeSign: Unknown object type."); -	} -} - -#endif // MODULE_REGEX_ENABLED diff --git a/platform/osx/export/codesign.h b/platform/osx/export/codesign.h deleted file mode 100644 index 3a08c0ea86..0000000000 --- a/platform/osx/export/codesign.h +++ /dev/null @@ -1,368 +0,0 @@ -/*************************************************************************/ -/*  codesign.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.                */ -/*************************************************************************/ - -// macOS code signature creation utility. -// -// Current implementation has the following limitation: -//  - Only version 11.3.0 signatures are supported. -//  - Only "framework" and "app" bundle types are supported. -//  - Page hash array scattering is not supported. -//  - Reading and writing binary property lists i snot supported (third-party frameworks with binary Info.plist will not work unless .plist is converted to text format). -//  - 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 - -#include "core/crypto/crypto_core.h" -#include "core/io/dir_access.h" -#include "core/io/file_access.h" -#include "core/object/ref_counted.h" - -#include "modules/modules_enabled.gen.h" // For regex. -#ifdef MODULE_REGEX_ENABLED -#include "modules/regex/regex.h" -#endif - -#include "plist.h" - -#ifdef MODULE_REGEX_ENABLED - -/*************************************************************************/ -/* CodeSignCodeResources                                                 */ -/*************************************************************************/ - -class CodeSignCodeResources { -public: -	enum class CRMatch { -		CR_MATCH_NO, -		CR_MATCH_YES, -		CR_MATCH_NESTED, -		CR_MATCH_OPTIONAL, -	}; - -private: -	struct CRFile { -		String name; -		String hash; -		String hash2; -		bool optional; -		bool nested; -		String requirements; -	}; - -	struct CRRule { -		String file_pattern; -		String key; -		int weight; -		bool store; -		CRRule() { -			weight = 1; -			store = true; -		} -		CRRule(const String &p_file_pattern, const String &p_key, int p_weight, bool p_store) { -			file_pattern = p_file_pattern; -			key = p_key; -			weight = p_weight; -			store = p_store; -		} -	}; - -	Vector<CRRule> rules1; -	Vector<CRRule> rules2; - -	Vector<CRFile> files1; -	Vector<CRFile> files2; - -	String hash_sha1_base64(const String &p_path); -	String hash_sha256_base64(const String &p_path); - -public: -	void add_rule1(const String &p_rule, const String &p_key = "", int p_weight = 0, bool p_store = true); -	void add_rule2(const String &p_rule, const String &p_key = "", int p_weight = 0, bool p_store = true); - -	CRMatch match_rules1(const String &p_path) const; -	CRMatch match_rules2(const String &p_path) const; - -	bool add_file1(const String &p_root, const String &p_path); -	bool add_file2(const String &p_root, const String &p_path); -	bool add_nested_file(const String &p_root, const String &p_path, const String &p_exepath); - -	bool add_folder_recursive(const String &p_root, const String &p_path = "", const String &p_main_exe_path = ""); - -	bool save_to_file(const String &p_path); -}; - -/*************************************************************************/ -/* CodeSignBlob                                                          */ -/*************************************************************************/ - -class CodeSignBlob : public RefCounted { -public: -	virtual PackedByteArray get_hash_sha1() const = 0; -	virtual PackedByteArray get_hash_sha256() const = 0; - -	virtual int get_size() const = 0; -	virtual uint32_t get_index_type() const = 0; - -	virtual void write_to_file(Ref<FileAccess> p_file) const = 0; -}; - -/*************************************************************************/ -/* CodeSignRequirements                                                  */ -/*************************************************************************/ - -// Note: Proper code generator is not implemented (any we probably won't ever need it), just a hardcoded bytecode for the limited set of cases. - -class CodeSignRequirements : public CodeSignBlob { -	PackedByteArray blob; - -	static inline size_t PAD(size_t s, size_t a) { -		return (s % a == 0) ? 0 : (a - s % a); -	} - -	_FORCE_INLINE_ void _parse_certificate_slot(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const; -	_FORCE_INLINE_ void _parse_key(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const; -	_FORCE_INLINE_ void _parse_oid_key(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const; -	_FORCE_INLINE_ void _parse_hash_string(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const; -	_FORCE_INLINE_ void _parse_value(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const; -	_FORCE_INLINE_ void _parse_date(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const; -	_FORCE_INLINE_ bool _parse_match(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const; - -public: -	CodeSignRequirements(); -	CodeSignRequirements(const PackedByteArray &p_data); - -	Vector<String> parse_requirements() const; - -	virtual PackedByteArray get_hash_sha1() const override; -	virtual PackedByteArray get_hash_sha256() const override; - -	virtual int get_size() const override; - -	virtual uint32_t get_index_type() const override { return 0x00000002; }; -	virtual void write_to_file(Ref<FileAccess> p_file) const override; -}; - -/*************************************************************************/ -/* CodeSignEntitlementsText                                             */ -/*************************************************************************/ - -// PList formatted entitlements. - -class CodeSignEntitlementsText : public CodeSignBlob { -	PackedByteArray blob; - -public: -	CodeSignEntitlementsText(); -	CodeSignEntitlementsText(const String &p_string); - -	virtual PackedByteArray get_hash_sha1() const override; -	virtual PackedByteArray get_hash_sha256() const override; - -	virtual int get_size() const override; - -	virtual uint32_t get_index_type() const override { return 0x00000005; }; -	virtual void write_to_file(Ref<FileAccess> p_file) const override; -}; - -/*************************************************************************/ -/* CodeSignEntitlementsBinary                                           */ -/*************************************************************************/ - -// ASN.1 serialized entitlements. - -class CodeSignEntitlementsBinary : public CodeSignBlob { -	PackedByteArray blob; - -public: -	CodeSignEntitlementsBinary(); -	CodeSignEntitlementsBinary(const String &p_string); - -	virtual PackedByteArray get_hash_sha1() const override; -	virtual PackedByteArray get_hash_sha256() const override; - -	virtual int get_size() const override; - -	virtual uint32_t get_index_type() const override { return 0x00000007; }; -	virtual void write_to_file(Ref<FileAccess> p_file) const override; -}; - -/*************************************************************************/ -/* CodeSignCodeDirectory                                                 */ -/*************************************************************************/ - -// Code Directory, runtime options, code segment and special structure hashes. - -class CodeSignCodeDirectory : public CodeSignBlob { -public: -	enum Slot { -		SLOT_INFO_PLIST = -1, -		SLOT_REQUIREMENTS = -2, -		SLOT_RESOURCES = -3, -		SLOT_APP_SPECIFIC = -4, // Unused. -		SLOT_ENTITLEMENTS = -5, -		SLOT_RESERVER1 = -6, // Unused. -		SLOT_DER_ENTITLEMENTS = -7, -	}; - -	enum CodeSignExecSegFlags { -		EXECSEG_MAIN_BINARY = 0x1, -		EXECSEG_ALLOW_UNSIGNED = 0x10, -		EXECSEG_DEBUGGER = 0x20, -		EXECSEG_JIT = 0x40, -		EXECSEG_SKIP_LV = 0x80, -		EXECSEG_CAN_LOAD_CDHASH = 0x100, -		EXECSEG_CAN_EXEC_CDHASH = 0x200, -	}; - -	enum CodeSignatureFlags { -		SIGNATURE_HOST = 0x0001, -		SIGNATURE_ADHOC = 0x0002, -		SIGNATURE_TASK_ALLOW = 0x0004, -		SIGNATURE_INSTALLER = 0x0008, -		SIGNATURE_FORCED_LV = 0x0010, -		SIGNATURE_INVALID_ALLOWED = 0x0020, -		SIGNATURE_FORCE_HARD = 0x0100, -		SIGNATURE_FORCE_KILL = 0x0200, -		SIGNATURE_FORCE_EXPIRATION = 0x0400, -		SIGNATURE_RESTRICT = 0x0800, -		SIGNATURE_ENFORCEMENT = 0x1000, -		SIGNATURE_LIBRARY_VALIDATION = 0x2000, -		SIGNATURE_ENTITLEMENTS_VALIDATED = 0x4000, -		SIGNATURE_NVRAM_UNRESTRICTED = 0x8000, -		SIGNATURE_RUNTIME = 0x10000, -		SIGNATURE_LINKER_SIGNED = 0x20000, -	}; - -private: -	PackedByteArray blob; - -	struct CodeDirectoryHeader { -		uint32_t version; // Using version 0x0020500. -		uint32_t flags; // // Option flags. -		uint32_t hash_offset; // Slot zero offset. -		uint32_t ident_offset; // Identifier string offset. -		uint32_t special_slots; // Nr. of slots with negative index. -		uint32_t code_slots; // Nr. of slots with index >= 0, (code_limit / page_size). -		uint32_t code_limit; // Everything before code signature load command offset. -		uint8_t hash_size; // 20 (SHA-1) or 32 (SHA-256). -		uint8_t hash_type; // 1 (SHA-1) or 2 (SHA-256). -		uint8_t platform; // Not used. -		uint8_t page_size; // Page size, power of two, 2^12 (4096). -		uint32_t spare2; // Not used. -		// Version 0x20100 -		uint32_t scatter_vector_offset; // Set to 0 and ignore. -		// Version 0x20200 -		uint32_t team_offset; // Team id string offset. -		// Version 0x20300 -		uint32_t spare3; // Not used. -		uint64_t code_limit_64; // Set to 0 and ignore. -		// Version 0x20400 -		uint64_t exec_seg_base; // Start of the signed code segmet. -		uint64_t exec_seg_limit; // Code segment (__TEXT) vmsize. -		uint64_t exec_seg_flags; // Executable segment flags. -		// Version 0x20500 -		uint32_t runtime; // Runtime version. -		uint32_t pre_encrypt_offset; // Set to 0 and ignore. -	}; - -	int32_t pages = 0; -	int32_t remain = 0; -	int32_t code_slots = 0; -	int32_t special_slots = 0; - -public: -	CodeSignCodeDirectory(); -	CodeSignCodeDirectory(uint8_t p_hash_size, uint8_t p_hash_type, bool p_main, const CharString &p_id, const CharString &p_team_id, uint32_t p_page_size, uint64_t p_exe_limit, uint64_t p_code_limit); - -	int32_t get_page_count(); -	int32_t get_page_remainder(); - -	bool set_hash_in_slot(const PackedByteArray &p_hash, int p_slot); - -	virtual PackedByteArray get_hash_sha1() const override; -	virtual PackedByteArray get_hash_sha256() const override; - -	virtual int get_size() const override; -	virtual uint32_t get_index_type() const override { return 0x00000000; }; - -	virtual void write_to_file(Ref<FileAccess> p_file) const override; -}; - -/*************************************************************************/ -/* CodeSignSignature                                                     */ -/*************************************************************************/ - -class CodeSignSignature : public CodeSignBlob { -	PackedByteArray blob; - -public: -	CodeSignSignature(); - -	virtual PackedByteArray get_hash_sha1() const override; -	virtual PackedByteArray get_hash_sha256() const override; - -	virtual int get_size() const override; -	virtual uint32_t get_index_type() const override { return 0x00010000; }; - -	virtual void write_to_file(Ref<FileAccess> p_file) const override; -}; - -/*************************************************************************/ -/* CodeSignSuperBlob                                                     */ -/*************************************************************************/ - -class CodeSignSuperBlob { -	Vector<Ref<CodeSignBlob>> blobs; - -public: -	bool add_blob(const Ref<CodeSignBlob> &p_blob); - -	int get_size() const; -	void write_to_file(Ref<FileAccess> p_file) const; -}; - -/*************************************************************************/ -/* CodeSign                                                              */ -/*************************************************************************/ - -class CodeSign { -	static PackedByteArray file_hash_sha1(const String &p_path); -	static PackedByteArray file_hash_sha256(const String &p_path); -	static Error _codesign_file(bool p_use_hardened_runtime, bool p_force, const String &p_info, const String &p_exe_path, const String &p_bundle_path, const String &p_ent_path, bool p_ios_bundle, String &r_error_msg); - -public: -	static Error codesign(bool p_use_hardened_runtime, bool p_force, const String &p_path, const String &p_ent_path, String &r_error_msg); -}; - -#endif // MODULE_REGEX_ENABLED - -#endif // CODESIGN_H diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp deleted file mode 100644 index bd35b39e9e..0000000000 --- a/platform/osx/export/export.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/*************************************************************************/ -/*  export.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 "export.h" - -#include "export_plugin.h" - -void register_osx_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; -	platform.instantiate(); - -	EditorExport::get_singleton()->add_export_platform(platform); -} diff --git a/platform/osx/export/export.h b/platform/osx/export/export.h deleted file mode 100644 index b386337a09..0000000000 --- a/platform/osx/export/export.h +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************/ -/*  export.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 OSX_EXPORT_H -#define OSX_EXPORT_H - -void register_osx_exporter(); - -#endif // OSX_EXPORT_H diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp deleted file mode 100644 index a22d7e5e3d..0000000000 --- a/platform/osx/export/export_plugin.cpp +++ /dev/null @@ -1,1673 +0,0 @@ -/*************************************************************************/ -/*  export_plugin.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 "export_plugin.h" - -#include "codesign.h" - -#include "editor/editor_node.h" -#include "editor/editor_paths.h" - -#include "modules/modules_enabled.gen.h" // For regex. - -void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { -	if (p_preset->get("texture_format/s3tc")) { -		r_features->push_back("s3tc"); -	} -	if (p_preset->get("texture_format/etc")) { -		r_features->push_back("etc"); -	} -	if (p_preset->get("texture_format/etc2")) { -		r_features->push_back("etc2"); -	} - -	r_features->push_back("64"); -} - -bool EditorExportPlatformOSX::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/")) { -			return false; -		} -	} - -	// These entitlements are required to run managed code, and are always enabled in Mono builds. -	if (Engine::get_singleton()->has_singleton("GodotSharp")) { -		if (p_option == "codesign/entitlements/allow_jit_code_execution" || p_option == "codesign/entitlements/allow_unsigned_executable_memory" || p_option == "codesign/entitlements/allow_dyld_environment_variables") { -			return false; -		} -	} -	return true; -} - -void EditorExportPlatformOSX::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"), "")); - -	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "application/copyright_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), true)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "")); - -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false)); - -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/disable_library_validation"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/audio_input"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/camera"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/location"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/address_book"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/calendars"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/debugging"), false)); - -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_usb"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_bluetooth"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_downloads", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_pictures", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array())); - -	r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); - -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "notarization/enable"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PLACEHOLDER_TEXT, "Enable two-factor authentication and provide app-specific password"), "")); -	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), "")); - -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); -	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false)); -} - -void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, Vector<uint8_t> &p_dest) { -	int src_len = p_size * p_size; - -	Vector<uint8_t> result; -	result.resize(src_len * 1.25); //temp vector for rle encoded data, make it 25% larger for worst case scenario -	int res_size = 0; - -	uint8_t buf[128]; -	int buf_size = 0; - -	int i = 0; -	while (i < src_len) { -		uint8_t cur = p_source.ptr()[i * 4 + p_ch]; - -		if (i < src_len - 2) { -			if ((p_source.ptr()[(i + 1) * 4 + p_ch] == cur) && (p_source.ptr()[(i + 2) * 4 + p_ch] == cur)) { -				if (buf_size > 0) { -					result.write[res_size++] = (uint8_t)(buf_size - 1); -					memcpy(&result.write[res_size], &buf, buf_size); -					res_size += buf_size; -					buf_size = 0; -				} - -				uint8_t lim = i + 130 >= src_len ? src_len - i - 1 : 130; -				bool hit_lim = true; - -				for (int j = 3; j <= lim; j++) { -					if (p_source.ptr()[(i + j) * 4 + p_ch] != cur) { -						hit_lim = false; -						i = i + j - 1; -						result.write[res_size++] = (uint8_t)(j - 3 + 0x80); -						result.write[res_size++] = cur; -						break; -					} -				} -				if (hit_lim) { -					result.write[res_size++] = (uint8_t)(lim - 3 + 0x80); -					result.write[res_size++] = cur; -					i = i + lim; -				} -			} else { -				buf[buf_size++] = cur; -				if (buf_size == 128) { -					result.write[res_size++] = (uint8_t)(buf_size - 1); -					memcpy(&result.write[res_size], &buf, buf_size); -					res_size += buf_size; -					buf_size = 0; -				} -			} -		} else { -			buf[buf_size++] = cur; -			result.write[res_size++] = (uint8_t)(buf_size - 1); -			memcpy(&result.write[res_size], &buf, buf_size); -			res_size += buf_size; -			buf_size = 0; -		} - -		i++; -	} - -	int ofs = p_dest.size(); -	p_dest.resize(p_dest.size() + res_size); -	memcpy(&p_dest.write[ofs], result.ptr(), res_size); -} - -void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { -	Ref<ImageTexture> it = memnew(ImageTexture); - -	Vector<uint8_t> data; - -	data.resize(8); -	data.write[0] = 'i'; -	data.write[1] = 'c'; -	data.write[2] = 'n'; -	data.write[3] = 's'; - -	struct MacOSIconInfo { -		const char *name; -		const char *mask_name; -		bool is_png; -		int size; -	}; - -	static const MacOSIconInfo icon_infos[] = { -		{ "ic10", "", true, 1024 }, //1024×1024 32-bit PNG and 512×512@2x 32-bit "retina" PNG -		{ "ic09", "", true, 512 }, //512×512 32-bit PNG -		{ "ic14", "", true, 512 }, //256×256@2x 32-bit "retina" PNG -		{ "ic08", "", true, 256 }, //256×256 32-bit PNG -		{ "ic13", "", true, 256 }, //128×128@2x 32-bit "retina" PNG -		{ "ic07", "", true, 128 }, //128×128 32-bit PNG -		{ "ic12", "", true, 64 }, //32×32@2× 32-bit "retina" PNG -		{ "ic11", "", true, 32 }, //16×16@2× 32-bit "retina" PNG -		{ "il32", "l8mk", false, 32 }, //32×32 24-bit RLE + 8-bit uncompressed mask -		{ "is32", "s8mk", false, 16 } //16×16 24-bit RLE + 8-bit uncompressed mask -	}; - -	for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { -		Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy? -		copy->convert(Image::FORMAT_RGBA8); -		copy->resize(icon_infos[i].size, icon_infos[i].size); - -		if (icon_infos[i].is_png) { -			// Encode PNG icon. -			it->set_image(copy); -			String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png"); -			ResourceSaver::save(path, it); - -			{ -				Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ); -				if (f.is_null()) { -					// Clean up generated file. -					DirAccess::remove_file_or_error(path); -					add_message(EXPORT_MESSAGE_ERROR, TTR("Icon Creation"), vformat(TTR("Could not open icon file \"%s\"."), path)); -					return; -				} - -				int ofs = data.size(); -				uint64_t len = f->get_length(); -				data.resize(data.size() + len + 8); -				f->get_buffer(&data.write[ofs + 8], len); -				len += 8; -				len = BSWAP32(len); -				memcpy(&data.write[ofs], icon_infos[i].name, 4); -				encode_uint32(len, &data.write[ofs + 4]); -			} - -			// Clean up generated file. -			DirAccess::remove_file_or_error(path); - -		} else { -			Vector<uint8_t> src_data = copy->get_data(); - -			//encode 24bit RGB RLE icon -			{ -				int ofs = data.size(); -				data.resize(data.size() + 8); - -				_rgba8_to_packbits_encode(0, icon_infos[i].size, src_data, data); // encode R -				_rgba8_to_packbits_encode(1, icon_infos[i].size, src_data, data); // encode G -				_rgba8_to_packbits_encode(2, icon_infos[i].size, src_data, data); // encode B - -				int len = data.size() - ofs; -				len = BSWAP32(len); -				memcpy(&data.write[ofs], icon_infos[i].name, 4); -				encode_uint32(len, &data.write[ofs + 4]); -			} - -			//encode 8bit mask uncompressed icon -			{ -				int ofs = data.size(); -				int len = copy->get_width() * copy->get_height(); -				data.resize(data.size() + len + 8); - -				for (int j = 0; j < len; j++) { -					data.write[ofs + 8 + j] = src_data.ptr()[j * 4 + 3]; -				} -				len += 8; -				len = BSWAP32(len); -				memcpy(&data.write[ofs], icon_infos[i].mask_name, 4); -				encode_uint32(len, &data.write[ofs + 4]); -			} -		} -	} - -	uint32_t total_len = data.size(); -	total_len = BSWAP32(total_len); -	encode_uint32(total_len, &data.write[4]); - -	p_data = data; -} - -void EditorExportPlatformOSX::_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()); -	Vector<String> lines = str.split("\n"); -	for (int i = 0; i < lines.size(); i++) { -		if (lines[i].find("$binary") != -1) { -			strnew += lines[i].replace("$binary", p_binary) + "\n"; -		} else if (lines[i].find("$name") != -1) { -			strnew += lines[i].replace("$name", ProjectSettings::get_singleton()->get("application/config/name")) + "\n"; -		} else if (lines[i].find("$bundle_identifier") != -1) { -			strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n"; -		} else if (lines[i].find("$short_version") != -1) { -			strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n"; -		} else if (lines[i].find("$version") != -1) { -			strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n"; -		} else if (lines[i].find("$signature") != -1) { -			strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n"; -		} else if (lines[i].find("$app_category") != -1) { -			String cat = p_preset->get("application/app_category"); -			strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n"; -		} else if (lines[i].find("$copyright") != -1) { -			strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; -		} else if (lines[i].find("$highres") != -1) { -			strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "\t<true/>" : "\t<false/>") + "\n"; -		} else if (lines[i].find("$usage_descriptions") != -1) { -			String descriptions; -			if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) { -				descriptions += "\t<key>NSMicrophoneUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/microphone_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/camera_usage_description")).is_empty()) { -				descriptions += "\t<key>NSCameraUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/camera_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/location_usage_description")).is_empty()) { -				descriptions += "\t<key>NSLocationUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/location_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/address_book_usage_description")).is_empty()) { -				descriptions += "\t<key>NSContactsUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/address_book_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/calendar_usage_description")).is_empty()) { -				descriptions += "\t<key>NSCalendarsUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/calendar_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/photos_library_usage_description")).is_empty()) { -				descriptions += "\t<key>NSPhotoLibraryUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/photos_library_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/desktop_folder_usage_description")).is_empty()) { -				descriptions += "\t<key>NSDesktopFolderUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/desktop_folder_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/documents_folder_usage_description")).is_empty()) { -				descriptions += "\t<key>NSDocumentsFolderUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/documents_folder_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/downloads_folder_usage_description")).is_empty()) { -				descriptions += "\t<key>NSDownloadsFolderUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/downloads_folder_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/network_volumes_usage_description")).is_empty()) { -				descriptions += "\t<key>NSNetworkVolumesUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/network_volumes_usage_description") + "</string>\n"; -			} -			if (!((String)p_preset->get("privacy/removable_volumes_usage_description")).is_empty()) { -				descriptions += "\t<key>NSRemovableVolumesUsageDescription</key>\n"; -				descriptions += "\t<string>" + (String)p_preset->get("privacy/removable_volumes_usage_description") + "</string>\n"; -			} -			if (!descriptions.is_empty()) { -				strnew += lines[i].replace("$usage_descriptions", descriptions); -			} -		} else { -			strnew += lines[i] + "\n"; -		} -	} - -	CharString cs = strnew.utf8(); -	plist.resize(cs.size() - 1); -	for (int i = 0; i < cs.size() - 1; i++) { -		plist.write[i] = cs[i]; -	} -} - -/** - * If we're running the OSX 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 -	List<String> args; - -	args.push_back("altool"); -	args.push_back("--notarize-app"); - -	args.push_back("--primary-bundle-id"); -	args.push_back(p_preset->get("application/bundle_identifier")); - -	args.push_back("--username"); -	args.push_back(p_preset->get("notarization/apple_id_name")); - -	args.push_back("--password"); -	args.push_back(p_preset->get("notarization/apple_id_password")); - -	args.push_back("--type"); -	args.push_back("osx"); - -	if (p_preset->get("notarization/apple_team_id")) { -		args.push_back("--asc-provider"); -		args.push_back(p_preset->get("notarization/apple_team_id")); -	} - -	args.push_back("--file"); -	args.push_back(p_path); - -	String str; -	Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, true); -	if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) { -		add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable.")); -		return err; -	} - -	print_verbose("altool (" + p_path + "):\n" + str); -	int rq_offset = str.find("RequestUUID"); -	if (rq_offset == -1) { -		add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed.")); -		return FAILED; -	} else { -		int next_nl = str.find("\n", rq_offset); -		String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14); -		add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid)); -		add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email.")); -		add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:")); -		add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\""); -		add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):")); -		add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\""); -	} - -#endif - -	return OK; -} - -Error EditorExportPlatformOSX::_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") == "-"); - -	if ((!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) || force_builtin_codesign) { -		print_verbose("using built-in codesign..."); -#ifdef MODULE_REGEX_ENABLED - -#ifdef OSX_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!")); -		} -		if (p_preset->get("codesign/hardened_runtime") && p_warn) { -			add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!")); -		} -#endif - -		String error_msg; -		Error err = CodeSign::codesign(false, p_preset->get("codesign/replace_existing_signature"), p_path, p_ent_path, error_msg); -		if (err != OK) { -			add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg)); -			return FAILED; -		} -#else -		add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module.")); -#endif -		return OK; -	} else { -		print_verbose("using external codesign..."); -		List<String> args; -		if (p_preset->get("codesign/timestamp")) { -			if (ad_hoc) { -				if (p_warn) { -					add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!")); -				} -			} else { -				args.push_back("--timestamp"); -			} -		} -		if (p_preset->get("codesign/hardened_runtime")) { -			if (ad_hoc) { -				if (p_warn) { -					add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!")); -				} -			} else { -				args.push_back("--options"); -				args.push_back("runtime"); -			} -		} - -		if (p_path.get_extension() != "dmg") { -			args.push_back("--entitlements"); -			args.push_back(p_ent_path); -		} - -		PackedStringArray user_args = p_preset->get("codesign/custom_options"); -		for (int i = 0; i < user_args.size(); i++) { -			String user_arg = user_args[i].strip_edges(); -			if (!user_arg.is_empty()) { -				args.push_back(user_arg); -			} -		} - -		args.push_back("-s"); -		if (ad_hoc) { -			args.push_back("-"); -		} else { -			args.push_back(p_preset->get("codesign/identity")); -		} - -		args.push_back("-v"); /* provide some more feedback */ - -		if (p_preset->get("codesign/replace_existing_signature")) { -			args.push_back("-f"); -		} - -		args.push_back(p_path); - -		String str; -		Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true); -		if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) { -			add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed.")); -			return err; -		} - -		print_verbose("codesign (" + p_path + "):\n" + str); -		if (str.find("no identity found") != -1) { -			add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found.")); -			return FAILED; -		} -		if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) { -			add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid entitlements file.")); -			return FAILED; -		} -		return OK; -	} -} - -Error EditorExportPlatformOSX::_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 -	static Vector<String> extensions_to_sign; - -	if (extensions_to_sign.is_empty()) { -		extensions_to_sign.push_back("dylib"); -		extensions_to_sign.push_back("framework"); -	} - -	Error dir_access_error; -	Ref<DirAccess> dir_access{ DirAccess::open(p_path, &dir_access_error) }; - -	if (dir_access_error != OK) { -		return dir_access_error; -	} - -	dir_access->list_dir_begin(); -	String current_file{ dir_access->get_next() }; -	while (!current_file.is_empty()) { -		String current_file_path{ p_path.plus_file(current_file) }; - -		if (current_file == ".." || current_file == ".") { -			current_file = dir_access->get_next(); -			continue; -		} - -		if (extensions_to_sign.find(current_file.get_extension()) > -1) { -			Error code_sign_error{ _code_sign(p_preset, current_file_path, p_ent_path, false) }; -			if (code_sign_error != OK) { -				return code_sign_error; -			} -		} else if (dir_access->current_is_dir()) { -			Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_should_error_on_non_code) }; -			if (code_sign_error != OK) { -				return code_sign_error; -			} -		} else if (p_should_error_on_non_code) { -			add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Cannot sign file %s."), current_file)); -			return Error::FAILED; -		} - -		current_file = dir_access->get_next(); -	} -#endif - -	return OK; -} - -Error EditorExportPlatformOSX::_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 err{ OK }; -	if (dir_access->dir_exists(p_src_path)) { -#ifndef UNIX_ENABLED -		add_message(EXPORT_MESSAGE_INFO, TTR("Export"), vformat(TTR("Relative symlinks are not supported, exported \"%s\" might be broken!"), p_src_path.get_file())); -#endif -		print_verbose("export framework: " + p_src_path + " -> " + p_in_app_path); -		err = dir_access->make_dir_recursive(p_in_app_path); -		if (err == OK) { -			err = dir_access->copy_dir(p_src_path, p_in_app_path, -1, true); -		} -	} else { -		print_verbose("export dylib: " + p_src_path + " -> " + p_in_app_path); -		err = dir_access->copy(p_src_path, p_in_app_path); -	} -	if (err == OK && p_sign_enabled) { -		if (dir_access->dir_exists(p_src_path) && p_src_path.get_extension().is_empty()) { -			// If it is a directory, find and sign all dynamic libraries. -			err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign); -		} else { -			err = _code_sign(p_preset, p_in_app_path, p_ent_path, false); -		} -	} -	return err; -} - -Error EditorExportPlatformOSX::_export_osx_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]) }; -		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) { -			break; -		} -	} -	return error; -} - -Error EditorExportPlatformOSX::_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)) { -		OS::get_singleton()->move_to_trash(p_dmg_path); -	} - -	args.push_back("create"); -	args.push_back(p_dmg_path); -	args.push_back("-volname"); -	args.push_back(p_pkg_name); -	args.push_back("-fs"); -	args.push_back("HFS+"); -	args.push_back("-srcfolder"); -	args.push_back(p_app_path_name); - -	String str; -	Error err = OS::get_singleton()->execute("hdiutil", args, &str, nullptr, true); -	if (err != OK) { -		add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("Could not start hdiutil executable.")); -		return err; -	} - -	print_verbose("hdiutil returned: " + str); -	if (str.find("create failed") != -1) { -		if (str.find("File exists") != -1) { -			add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("`hdiutil create` failed - file exists.")); -		} else { -			add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("`hdiutil create` failed.")); -		} -		return FAILED; -	} - -	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) { -	Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); -	if (f.is_null()) { -		add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path)); -		return ERR_CANT_CREATE; -	} - -	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 + "\" \"$@\""); - -	return OK; -} - -Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { -	ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); - -	String src_pkg_name; - -	EditorProgress ep("export", "Exporting for OSX", 3, true); - -	if (p_debug) { -		src_pkg_name = p_preset->get("custom_template/debug"); -	} else { -		src_pkg_name = p_preset->get("custom_template/release"); -	} - -	if (src_pkg_name.is_empty()) { -		String err; -		src_pkg_name = find_export_template("osx.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; -		} -	} - -	if (!DirAccess::exists(p_path.get_base_dir())) { -		add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("The given export path doesn't exist.")); -		return ERR_FILE_BAD_PATH; -	} - -	Ref<FileAccess> io_fa; -	zlib_filefunc_def io = zipio_create_io(&io_fa); - -	if (ep.step(TTR("Creating app bundle"), 0)) { -		return ERR_SKIP; -	} - -	unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); -	if (!src_pkg_zip) { -		add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not find template app to export: \"%s\"."), src_pkg_name)); -		return ERR_FILE_NOT_FOUND; -	} - -	int ret = unzGoToFirstFile(src_pkg_zip); - -	String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".64"; - -	String pkg_name; -	if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { -		pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); -	} else { -		pkg_name = "Unnamed"; -	} - -	pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name); - -	String export_format; -	if (use_dmg() && p_path.ends_with("dmg")) { -		export_format = "dmg"; -	} else if (p_path.ends_with("zip")) { -		export_format = "zip"; -	} else if (p_path.ends_with("app")) { -		export_format = "app"; -	} else { -		add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid export format.")); -		return ERR_CANT_CREATE; -	} - -	// Create our application bundle. -	String tmp_app_dir_name = pkg_name + ".app"; -	String tmp_base_path_name; -	String tmp_app_path_name; -	String scr_path; -	if (export_format == "app") { -		tmp_base_path_name = p_path.get_base_dir(); -		tmp_app_path_name = p_path; -		scr_path = p_path.get_basename() + ".command"; -	} else { -		tmp_base_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name); -		tmp_app_path_name = tmp_base_path_name.plus_file(tmp_app_dir_name); -		scr_path = tmp_base_path_name.plus_file(pkg_name + ".command"); -	} - -	print_verbose("Exporting to " + tmp_app_path_name); - -	Error err = OK; - -	Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_base_path_name); -	if (tmp_app_dir.is_null()) { -		add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory: \"%s\"."), tmp_base_path_name)); -		err = ERR_CANT_CREATE; -	} - -	DirAccess::remove_file_or_error(scr_path); -	if (DirAccess::exists(tmp_app_path_name)) { -		String old_dir = tmp_app_dir->get_current_dir(); -		if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) { -			tmp_app_dir->erase_contents_recursive(); -			tmp_app_dir->change_dir(old_dir); -		} -	} - -	Array helpers = p_preset->get("codesign/entitlements/app_sandbox/helper_executables"); - -	// Create our folder structure. -	if (err == OK) { -		print_verbose("Creating " + tmp_app_path_name + "/Contents/MacOS"); -		err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS"); -		if (err != OK) { -			add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), tmp_app_path_name + "/Contents/MacOS")); -		} -	} - -	if (err == OK) { -		print_verbose("Creating " + tmp_app_path_name + "/Contents/Frameworks"); -		err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks"); -		if (err != OK) { -			add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), tmp_app_path_name + "/Contents/Frameworks")); -		} -	} - -	if ((err == OK) && helpers.size() > 0) { -		print_line("Creating " + tmp_app_path_name + "/Contents/Helpers"); -		err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Helpers"); -		if (err != OK) { -			add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), tmp_app_path_name + "/Contents/Helpers")); -		} -	} - -	if (err == OK) { -		print_verbose("Creating " + tmp_app_path_name + "/Contents/Resources"); -		err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); -		if (err != OK) { -			add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), tmp_app_path_name + "/Contents/Resources")); -		} -	} - -	Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized"); -	Dictionary microphone_usage_descriptions = p_preset->get("privacy/microphone_usage_description_localized"); -	Dictionary camera_usage_descriptions = p_preset->get("privacy/camera_usage_description_localized"); -	Dictionary location_usage_descriptions = p_preset->get("privacy/location_usage_description_localized"); -	Dictionary address_book_usage_descriptions = p_preset->get("privacy/address_book_usage_description_localized"); -	Dictionary calendar_usage_descriptions = p_preset->get("privacy/calendar_usage_description_localized"); -	Dictionary photos_library_usage_descriptions = p_preset->get("privacy/photos_library_usage_description_localized"); -	Dictionary desktop_folder_usage_descriptions = p_preset->get("privacy/desktop_folder_usage_description_localized"); -	Dictionary documents_folder_usage_descriptions = p_preset->get("privacy/documents_folder_usage_description_localized"); -	Dictionary downloads_folder_usage_descriptions = p_preset->get("privacy/downloads_folder_usage_description_localized"); -	Dictionary network_volumes_usage_descriptions = p_preset->get("privacy/network_volumes_usage_description_localized"); -	Dictionary removable_volumes_usage_descriptions = p_preset->get("privacy/removable_volumes_usage_description_localized"); -	Dictionary copyrights = p_preset->get("application/copyright_localized"); - -	Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations"); -	if (translations.size() > 0) { -		{ -			String fname = tmp_app_path_name + "/Contents/Resources/en.lproj"; -			tmp_app_dir->make_dir_recursive(fname); -			Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); -			f->store_line("/* Localized versions of Info.plist keys */"); -			f->store_line(""); -			f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";"); -			if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) { -				f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/camera_usage_description")).is_empty()) { -				f->store_line("NSCameraUsageDescription = \"" + p_preset->get("privacy/camera_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/location_usage_description")).is_empty()) { -				f->store_line("NSLocationUsageDescription = \"" + p_preset->get("privacy/location_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/address_book_usage_description")).is_empty()) { -				f->store_line("NSContactsUsageDescription = \"" + p_preset->get("privacy/address_book_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/calendar_usage_description")).is_empty()) { -				f->store_line("NSCalendarsUsageDescription = \"" + p_preset->get("privacy/calendar_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/photos_library_usage_description")).is_empty()) { -				f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photos_library_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/desktop_folder_usage_description")).is_empty()) { -				f->store_line("NSDesktopFolderUsageDescription = \"" + p_preset->get("privacy/desktop_folder_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/documents_folder_usage_description")).is_empty()) { -				f->store_line("NSDocumentsFolderUsageDescription = \"" + p_preset->get("privacy/documents_folder_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/downloads_folder_usage_description")).is_empty()) { -				f->store_line("NSDownloadsFolderUsageDescription = \"" + p_preset->get("privacy/downloads_folder_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/network_volumes_usage_description")).is_empty()) { -				f->store_line("NSNetworkVolumesUsageDescription = \"" + p_preset->get("privacy/network_volumes_usage_description").operator String() + "\";"); -			} -			if (!((String)p_preset->get("privacy/removable_volumes_usage_description")).is_empty()) { -				f->store_line("NSRemovableVolumesUsageDescription = \"" + p_preset->get("privacy/removable_volumes_usage_description").operator String() + "\";"); -			} -			f->store_line("NSHumanReadableCopyright = \"" + p_preset->get("application/copyright").operator String() + "\";"); -		} - -		for (const String &E : translations) { -			Ref<Translation> tr = ResourceLoader::load(E); -			if (tr.is_valid()) { -				String lang = tr->get_locale(); -				String fname = tmp_app_path_name + "/Contents/Resources/" + lang + ".lproj"; -				tmp_app_dir->make_dir_recursive(fname); -				Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); -				f->store_line("/* Localized versions of Info.plist keys */"); -				f->store_line(""); -				if (appnames.has(lang)) { -					f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); -				} -				if (microphone_usage_descriptions.has(lang)) { -					f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); -				} -				if (camera_usage_descriptions.has(lang)) { -					f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); -				} -				if (location_usage_descriptions.has(lang)) { -					f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String() + "\";"); -				} -				if (address_book_usage_descriptions.has(lang)) { -					f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String() + "\";"); -				} -				if (calendar_usage_descriptions.has(lang)) { -					f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String() + "\";"); -				} -				if (photos_library_usage_descriptions.has(lang)) { -					f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String() + "\";"); -				} -				if (desktop_folder_usage_descriptions.has(lang)) { -					f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String() + "\";"); -				} -				if (documents_folder_usage_descriptions.has(lang)) { -					f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String() + "\";"); -				} -				if (downloads_folder_usage_descriptions.has(lang)) { -					f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String() + "\";"); -				} -				if (network_volumes_usage_descriptions.has(lang)) { -					f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String() + "\";"); -				} -				if (removable_volumes_usage_descriptions.has(lang)) { -					f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String() + "\";"); -				} -				if (copyrights.has(lang)) { -					f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String() + "\";"); -				} -			} -		} -	} - -	// Now process our template. -	bool found_binary = false; -	Vector<String> dylibs_found; - -	while (ret == UNZ_OK && err == OK) { -		bool is_execute = false; - -		// Get filename. -		unz_file_info info; -		char fname[16384]; -		ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0); -		if (ret != UNZ_OK) { -			break; -		} - -		String file = String::utf8(fname); - -		Vector<uint8_t> data; -		data.resize(info.uncompressed_size); - -		// Read. -		unzOpenCurrentFile(src_pkg_zip); -		unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size()); -		unzCloseCurrentFile(src_pkg_zip); - -		// Write. -		file = file.replace_first("osx_template.app/", ""); - -		if (((info.external_fa >> 16L) & 0120000) == 0120000) { -#ifndef UNIX_ENABLED -			add_message(EXPORT_MESSAGE_INFO, TTR("Export"), TTR("Relative symlinks are not supported on this OS, the exported project might be broken!")); -#endif -			// Handle symlinks in the archive. -			file = tmp_app_path_name.plus_file(file); -			if (err == OK) { -				err = tmp_app_dir->make_dir_recursive(file.get_base_dir()); -				if (err != OK) { -					add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), file.get_base_dir())); -				} -			} -			if (err == OK) { -				String lnk_data = String::utf8((const char *)data.ptr(), data.size()); -				err = tmp_app_dir->create_link(lnk_data, file); -				if (err != OK) { -					add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not created symlink \"%s\" -> \"%s\"."), lnk_data, file)); -				} -				print_verbose(vformat("ADDING SYMLINK %s => %s\n", file, lnk_data)); -			} - -			ret = unzGoToNextFile(src_pkg_zip); -			continue; // next -		} - -		if (file == "Contents/Info.plist") { -			_fix_plist(p_preset, data, pkg_name); -		} - -		if (file.begins_with("Contents/MacOS/godot_")) { -			if (file != "Contents/MacOS/" + binary_to_use) { -				ret = unzGoToNextFile(src_pkg_zip); -				continue; // skip -			} -			found_binary = true; -			is_execute = true; -			file = "Contents/MacOS/" + pkg_name; -		} - -		if (file == "Contents/Resources/icon.icns") { -			// See if there is an icon. -			String iconpath; -			if (p_preset->get("application/icon") != "") { -				iconpath = p_preset->get("application/icon"); -			} else { -				iconpath = ProjectSettings::get_singleton()->get("application/config/icon"); -			} - -			if (!iconpath.is_empty()) { -				if (iconpath.get_extension() == "icns") { -					Ref<FileAccess> icon = FileAccess::open(iconpath, FileAccess::READ); -					if (icon.is_valid()) { -						data.resize(icon->get_length()); -						icon->get_buffer(&data.write[0], icon->get_length()); -					} -				} else { -					Ref<Image> icon; -					icon.instantiate(); -					icon->load(iconpath); -					if (!icon->is_empty()) { -						_make_icon(icon, data); -					} -				} -			} -		} - -		if (data.size() > 0) { -			if (file.find("/data.mono.osx.64.release_debug/") != -1) { -				if (!p_debug) { -					ret = unzGoToNextFile(src_pkg_zip); -					continue; // skip -				} -				file = file.replace("/data.mono.osx.64.release_debug/", "/GodotSharp/"); -			} -			if (file.find("/data.mono.osx.64.release/") != -1) { -				if (p_debug) { -					ret = unzGoToNextFile(src_pkg_zip); -					continue; // skip -				} -				file = file.replace("/data.mono.osx.64.release/", "/GodotSharp/"); -			} - -			if (file.ends_with(".dylib")) { -				dylibs_found.push_back(file); -			} - -			print_verbose("ADDING: " + file + " size: " + itos(data.size())); - -			// Write it into our application bundle. -			file = tmp_app_path_name.plus_file(file); -			if (err == OK) { -				err = tmp_app_dir->make_dir_recursive(file.get_base_dir()); -				if (err != OK) { -					add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create directory \"%s\"."), file.get_base_dir())); -				} -			} -			if (err == OK) { -				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); -					} -				} else { -					add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not open \"%s\"."), file)); -					err = ERR_CANT_CREATE; -				} -			} -		} - -		ret = unzGoToNextFile(src_pkg_zip); -	} - -	// We're done with our source zip. -	unzClose(src_pkg_zip); - -	if (!found_binary) { -		add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Requested template binary \"%s\" not found. It might be missing from your template archive."), binary_to_use)); -		err = ERR_FILE_NOT_FOUND; -	} - -	// Save console script. -	if (err == OK) { -		int con_scr = p_preset->get("debug/export_console_script"); -		if ((con_scr == 1 && p_debug) || (con_scr == 2)) { -			err = _export_debug_script(p_preset, pkg_name, tmp_app_path_name.get_file() + "/Contents/MacOS/" + pkg_name, scr_path); -			FileAccess::set_unix_permissions(scr_path, 0755); -			if (err != OK) { -				add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not create console script.")); -			} -		} -	} - -	if (err == OK) { -		if (ep.step(TTR("Making PKG"), 1)) { -			return ERR_SKIP; -		} - -		String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck"; -		Vector<SharedObject> shared_objects; -		err = save_pack(p_preset, p_debug, pack_path, &shared_objects); - -		// See if we can code sign our new package. -		bool sign_enabled = p_preset->get("codesign/enable"); - -		String ent_path = p_preset->get("codesign/entitlements/custom_file"); -		String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements"); -		if (sign_enabled && (ent_path.is_empty())) { -			ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements"); - -			Ref<FileAccess> ent_f = FileAccess::open(ent_path, FileAccess::WRITE); -			if (ent_f.is_valid()) { -				ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); -				ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"); -				ent_f->store_line("<plist version=\"1.0\">"); -				ent_f->store_line("<dict>"); -				if (Engine::get_singleton()->has_singleton("GodotSharp")) { -					// These entitlements are required to run managed code, and are always enabled in Mono builds. -					ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>"); -					ent_f->store_line("<true/>"); -					ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>"); -					ent_f->store_line("<true/>"); -					ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>"); -					ent_f->store_line("<true/>"); -				} else { -					if ((bool)p_preset->get("codesign/entitlements/allow_jit_code_execution")) { -						ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((bool)p_preset->get("codesign/entitlements/allow_unsigned_executable_memory")) { -						ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((bool)p_preset->get("codesign/entitlements/allow_dyld_environment_variables")) { -						ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>"); -						ent_f->store_line("<true/>"); -					} -				} - -				if ((bool)p_preset->get("codesign/entitlements/disable_library_validation")) { -					ent_f->store_line("<key>com.apple.security.cs.disable-library-validation</key>"); -					ent_f->store_line("<true/>"); -				} -				if ((bool)p_preset->get("codesign/entitlements/audio_input")) { -					ent_f->store_line("<key>com.apple.security.device.audio-input</key>"); -					ent_f->store_line("<true/>"); -				} -				if ((bool)p_preset->get("codesign/entitlements/camera")) { -					ent_f->store_line("<key>com.apple.security.device.camera</key>"); -					ent_f->store_line("<true/>"); -				} -				if ((bool)p_preset->get("codesign/entitlements/location")) { -					ent_f->store_line("<key>com.apple.security.personal-information.location</key>"); -					ent_f->store_line("<true/>"); -				} -				if ((bool)p_preset->get("codesign/entitlements/address_book")) { -					ent_f->store_line("<key>com.apple.security.personal-information.addressbook</key>"); -					ent_f->store_line("<true/>"); -				} -				if ((bool)p_preset->get("codesign/entitlements/calendars")) { -					ent_f->store_line("<key>com.apple.security.personal-information.calendars</key>"); -					ent_f->store_line("<true/>"); -				} -				if ((bool)p_preset->get("codesign/entitlements/photos_library")) { -					ent_f->store_line("<key>com.apple.security.personal-information.photos-library</key>"); -					ent_f->store_line("<true/>"); -				} -				if ((bool)p_preset->get("codesign/entitlements/apple_events")) { -					ent_f->store_line("<key>com.apple.security.automation.apple-events</key>"); -					ent_f->store_line("<true/>"); -				} -				if ((bool)p_preset->get("codesign/entitlements/debugging")) { -					ent_f->store_line("<key>com.apple.security.get-task-allow</key>"); -					ent_f->store_line("<true/>"); -				} - -				if ((bool)p_preset->get("codesign/entitlements/app_sandbox/enabled")) { -					ent_f->store_line("<key>com.apple.security.app-sandbox</key>"); -					ent_f->store_line("<true/>"); - -					if ((bool)p_preset->get("codesign/entitlements/app_sandbox/network_server")) { -						ent_f->store_line("<key>com.apple.security.network.server</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((bool)p_preset->get("codesign/entitlements/app_sandbox/network_client")) { -						ent_f->store_line("<key>com.apple.security.network.client</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((bool)p_preset->get("codesign/entitlements/app_sandbox/device_usb")) { -						ent_f->store_line("<key>com.apple.security.device.usb</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((bool)p_preset->get("codesign/entitlements/app_sandbox/device_bluetooth")) { -						ent_f->store_line("<key>com.apple.security.device.bluetooth</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_downloads") == 1) { -						ent_f->store_line("<key>com.apple.security.files.downloads.read-only</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_downloads") == 2) { -						ent_f->store_line("<key>com.apple.security.files.downloads.read-write</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_pictures") == 1) { -						ent_f->store_line("<key>com.apple.security.files.pictures.read-only</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_pictures") == 2) { -						ent_f->store_line("<key>com.apple.security.files.pictures.read-write</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_music") == 1) { -						ent_f->store_line("<key>com.apple.security.files.music.read-only</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_music") == 2) { -						ent_f->store_line("<key>com.apple.security.files.music.read-write</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_movies") == 1) { -						ent_f->store_line("<key>com.apple.security.files.movies.read-only</key>"); -						ent_f->store_line("<true/>"); -					} -					if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_movies") == 2) { -						ent_f->store_line("<key>com.apple.security.files.movies.read-write</key>"); -						ent_f->store_line("<true/>"); -					} -				} - -				ent_f->store_line("</dict>"); -				ent_f->store_line("</plist>"); -			} else { -				add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not create entitlements file.")); -				err = ERR_CANT_CREATE; -			} - -			if ((err == OK) && helpers.size() > 0) { -				ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE); -				if (ent_f.is_valid()) { -					ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); -					ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"); -					ent_f->store_line("<plist version=\"1.0\">"); -					ent_f->store_line("<dict>"); -					ent_f->store_line("<key>com.apple.security.app-sandbox</key>"); -					ent_f->store_line("<true/>"); -					ent_f->store_line("<key>com.apple.security.inherit</key>"); -					ent_f->store_line("<true/>"); -					ent_f->store_line("</dict>"); -					ent_f->store_line("</plist>"); -				} else { -					add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not create helper entitlements file.")); -					err = ERR_CANT_CREATE; -				} -			} -		} - -		if ((err == OK) && helpers.size() > 0) { -			Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); -			for (int i = 0; i < helpers.size(); i++) { -				String hlp_path = helpers[i]; -				err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file()); -				if (err == OK && sign_enabled) { -					err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false); -				} -				FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755); -			} -		} - -		bool ad_hoc = true; -		if (err == OK) { -#ifdef OSX_ENABLED -			String sign_identity = p_preset->get("codesign/identity"); -#else -			String sign_identity = "-"; -#endif -			ad_hoc = (sign_identity == "" || sign_identity == "-"); -			bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation"); -			if ((!dylibs_found.is_empty() || !shared_objects.is_empty()) && sign_enabled && ad_hoc && !lib_validation) { -				add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries.")); -				err = ERR_CANT_CREATE; -			} -		} - -		if (err == OK) { -			Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); -			for (int i = 0; i < shared_objects.size(); i++) { -				String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path); -				if (shared_objects[i].target.is_empty()) { -					String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(); -					err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true); -				} else { -					String path_in_app = tmp_app_path_name.plus_file(shared_objects[i].target).plus_file(src_path.get_file()); -					err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, false); -				} -				if (err != OK) { -					break; -				} -			} - -			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); -				if (err != OK) { -					break; -				} -			} -		} - -		if (sign_enabled) { -			for (int i = 0; i < dylibs_found.size(); i++) { -				if (err == OK) { -					err = _code_sign(p_preset, tmp_app_path_name + "/" + dylibs_found[i], ent_path, false); -				} -			} -		} - -		if (err == OK && sign_enabled) { -			if (ep.step(TTR("Code signing bundle"), 2)) { -				return ERR_SKIP; -			} -			err = _code_sign(p_preset, tmp_app_path_name, ent_path); -		} - -		if (export_format == "dmg") { -			// Create a DMG. -			if (err == OK) { -				if (ep.step(TTR("Making DMG"), 3)) { -					return ERR_SKIP; -				} -				err = _create_dmg(p_path, pkg_name, tmp_base_path_name); -			} -			// Sign DMG. -			if (err == OK && sign_enabled && !ad_hoc) { -				if (ep.step(TTR("Code signing DMG"), 3)) { -					return ERR_SKIP; -				} -				err = _code_sign(p_preset, p_path, ent_path, false); -			} -		} else if (export_format == "zip") { -			// Create ZIP. -			if (err == OK) { -				if (ep.step(TTR("Making ZIP"), 3)) { -					return ERR_SKIP; -				} -				if (FileAccess::exists(p_path)) { -					OS::get_singleton()->move_to_trash(p_path); -				} - -				Ref<FileAccess> io_fa_dst; -				zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst); -				zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst); - -				_zip_folder_recursive(zip, tmp_base_path_name, "", pkg_name); - -				zipClose(zip, nullptr); -			} -		} - -#ifdef OSX_ENABLED -		bool noto_enabled = p_preset->get("notarization/enable"); -		if (err == OK && noto_enabled) { -			if (export_format == "app") { -				add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("Notarization requires the app to be archived first, select the DMG or ZIP export format instead.")); -			} else { -				if (ep.step(TTR("Sending archive for notarization"), 4)) { -					return ERR_SKIP; -				} -				err = _notarize(p_preset, p_path); -			} -		} -#endif - -		// Clean up temporary entitlements files. -		DirAccess::remove_file_or_error(hlp_ent_path); - -		// Clean up temporary .app dir and generated entitlements. -		if ((String)(p_preset->get("codesign/entitlements/custom_file")) == "") { -			tmp_app_dir->remove(ent_path); -		} -		if (export_format != "app") { -			if (tmp_app_dir->change_dir(tmp_base_path_name) == OK) { -				tmp_app_dir->erase_contents_recursive(); -				tmp_app_dir->change_dir(".."); -				tmp_app_dir->remove(pkg_name); -			} -		} -	} - -	return err; -} - -void EditorExportPlatformOSX::_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); -	da->list_dir_begin(); -	String f = da->get_next(); -	while (!f.is_empty()) { -		if (f == "." || f == "..") { -			f = da->get_next(); -			continue; -		} -		if (da->is_link(f)) { -			OS::Time time = OS::get_singleton()->get_time(); -			OS::Date date = OS::get_singleton()->get_date(); - -			zip_fileinfo zipfi; -			zipfi.tmz_date.tm_hour = time.hour; -			zipfi.tmz_date.tm_mday = date.day; -			zipfi.tmz_date.tm_min = time.minute; -			zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ -			zipfi.tmz_date.tm_sec = time.second; -			zipfi.tmz_date.tm_year = date.year; -			zipfi.dosDate = 0; -			// 0120000: symbolic link type -			// 0000755: permissions rwxr-xr-x -			// 0000644: permissions rw-r--r-- -			uint32_t _mode = 0120644; -			zipfi.external_fa = (_mode << 16L) | !(_mode & 0200); -			zipfi.internal_fa = 0; - -			zipOpenNewFileInZip4(p_zip, -					p_folder.plus_file(f).utf8().get_data(), -					&zipfi, -					nullptr, -					0, -					nullptr, -					0, -					nullptr, -					Z_DEFLATED, -					Z_DEFAULT_COMPRESSION, -					0, -					-MAX_WBITS, -					DEF_MEM_LEVEL, -					Z_DEFAULT_STRATEGY, -					nullptr, -					0, -					0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions -					0); - -			String target = da->read_link(f); -			zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size()); -			zipCloseFileInZip(p_zip); -		} else if (da->current_is_dir()) { -			_zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name); -		} else { -			bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers") || f.ends_with(".command"); - -			OS::Time time = OS::get_singleton()->get_time(); -			OS::Date date = OS::get_singleton()->get_date(); - -			zip_fileinfo zipfi; -			zipfi.tmz_date.tm_hour = time.hour; -			zipfi.tmz_date.tm_mday = date.day; -			zipfi.tmz_date.tm_min = time.minute; -			zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ -			zipfi.tmz_date.tm_sec = time.second; -			zipfi.tmz_date.tm_year = date.year; -			zipfi.dosDate = 0; -			// 0100000: regular file type -			// 0000755: permissions rwxr-xr-x -			// 0000644: permissions rw-r--r-- -			uint32_t _mode = (is_executable ? 0100755 : 0100644); -			zipfi.external_fa = (_mode << 16L) | !(_mode & 0200); -			zipfi.internal_fa = 0; - -			zipOpenNewFileInZip4(p_zip, -					p_folder.plus_file(f).utf8().get_data(), -					&zipfi, -					nullptr, -					0, -					nullptr, -					0, -					nullptr, -					Z_DEFLATED, -					Z_DEFAULT_COMPRESSION, -					0, -					-MAX_WBITS, -					DEF_MEM_LEVEL, -					Z_DEFAULT_STRATEGY, -					nullptr, -					0, -					0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions -					0); - -			Ref<FileAccess> fa = FileAccess::open(dir.plus_file(f), FileAccess::READ); -			if (fa.is_null()) { -				add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.plus_file(f))); -				return; -			} -			const int bufsize = 16384; -			uint8_t buf[bufsize]; - -			while (true) { -				uint64_t got = fa->get_buffer(buf, bufsize); -				if (got == 0) { -					break; -				} -				zipWriteInFileInZip(p_zip, buf, got); -			} - -			zipCloseFileInZip(p_zip); -		} -		f = da->get_next(); -	} -	da->list_dir_end(); -} - -bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { -	String err; -	bool valid = false; - -	// Look for export templates (custom templates). -	bool dvalid = false; -	bool rvalid = false; - -	if (p_preset->get("custom_template/debug") != "") { -		dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); -		if (!dvalid) { -			err += TTR("Custom debug template not found.") + "\n"; -		} -	} -	if (p_preset->get("custom_template/release") != "") { -		rvalid = FileAccess::exists(p_preset->get("custom_template/release")); -		if (!rvalid) { -			err += TTR("Custom release template not found.") + "\n"; -		} -	} - -	// Look for export templates (official templates, check only is custom templates are not set). -	if (!dvalid || !rvalid) { -		dvalid = exists_export_template("osx.zip", &err); -		rvalid = dvalid; // Both in the same ZIP. -	} - -	valid = dvalid || rvalid; -	r_missing_templates = !valid; - -	String identifier = p_preset->get("application/bundle_identifier"); -	String pn_err; -	if (!is_package_name_valid(identifier, &pn_err)) { -		err += TTR("Invalid bundle identifier:") + " " + pn_err + "\n"; -		valid = false; -	} - -	bool sign_enabled = p_preset->get("codesign/enable"); - -#ifdef OSX_ENABLED -	bool noto_enabled = p_preset->get("notarization/enable"); -	bool ad_hoc = ((p_preset->get("codesign/identity") == "") || (p_preset->get("codesign/identity") == "-")); - -	if (!ad_hoc && (bool)EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign")) { -		err += TTR("Warning: Built-in \"codesign\" is selected in the Editor Settings. Code signing is limited to ad-hoc signature only.") + "\n"; -	} -	if (!ad_hoc && !FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) { -		err += TTR("Warning: Xcode command line tools are not installed, using built-in \"codesign\". Code signing is limited to ad-hoc signature only.") + "\n"; -	} - -	if (noto_enabled) { -		if (ad_hoc) { -			err += TTR("Notarization: Notarization with an ad-hoc signature is not supported.") + "\n"; -			valid = false; -		} -		if (!sign_enabled) { -			err += TTR("Notarization: Code signing is required for notarization.") + "\n"; -			valid = false; -		} -		if (!(bool)p_preset->get("codesign/hardened_runtime")) { -			err += TTR("Notarization: Hardened runtime is required for notarization.") + "\n"; -			valid = false; -		} -		if (!(bool)p_preset->get("codesign/timestamp")) { -			err += TTR("Notarization: Timestamping is required for notarization.") + "\n"; -			valid = false; -		} -		if (p_preset->get("notarization/apple_id_name") == "") { -			err += TTR("Notarization: Apple ID name not specified.") + "\n"; -			valid = false; -		} -		if (p_preset->get("notarization/apple_id_password") == "") { -			err += TTR("Notarization: Apple ID password not specified.") + "\n"; -			valid = false; -		} -	} else { -		err += TTR("Warning: Notarization is disabled. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n"; -		if (!sign_enabled) { -			err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n"; -		} else { -			if ((bool)p_preset->get("codesign/hardened_runtime") && ad_hoc) { -				err += TTR("Hardened Runtime is not compatible with ad-hoc signature, and will be disabled!") + "\n"; -			} -			if ((bool)p_preset->get("codesign/timestamp") && ad_hoc) { -				err += TTR("Timestamping is not compatible with ad-hoc signature, and will be disabled!") + "\n"; -			} -		} -	} -#else -	err += TTR("Warning: Notarization is not supported from this OS. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n"; -	if (!sign_enabled) { -		err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n"; -	} -#endif - -	if (sign_enabled) { -		if ((bool)p_preset->get("codesign/entitlements/audio_input") && ((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) { -			err += TTR("Privacy: Microphone access is enabled, but usage description is not specified.") + "\n"; -			valid = false; -		} -		if ((bool)p_preset->get("codesign/entitlements/camera") && ((String)p_preset->get("privacy/camera_usage_description")).is_empty()) { -			err += TTR("Privacy: Camera access is enabled, but usage description is not specified.") + "\n"; -			valid = false; -		} -		if ((bool)p_preset->get("codesign/entitlements/location") && ((String)p_preset->get("privacy/location_usage_description")).is_empty()) { -			err += TTR("Privacy: Location information access is enabled, but usage description is not specified.") + "\n"; -			valid = false; -		} -		if ((bool)p_preset->get("codesign/entitlements/address_book") && ((String)p_preset->get("privacy/address_book_usage_description")).is_empty()) { -			err += TTR("Privacy: Address book access is enabled, but usage description is not specified.") + "\n"; -			valid = false; -		} -		if ((bool)p_preset->get("codesign/entitlements/calendars") && ((String)p_preset->get("privacy/calendar_usage_description")).is_empty()) { -			err += TTR("Privacy: Calendar access is enabled, but usage description is not specified.") + "\n"; -			valid = false; -		} -		if ((bool)p_preset->get("codesign/entitlements/photos_library") && ((String)p_preset->get("privacy/photos_library_usage_description")).is_empty()) { -			err += TTR("Privacy: Photo library access is enabled, but usage description is not specified.") + "\n"; -			valid = false; -		} -	} - -	if (!err.is_empty()) { -		r_error = err; -	} -	return valid; -} - -EditorExportPlatformOSX::EditorExportPlatformOSX() { -	logo = ImageTexture::create_from_image(memnew(Image(_osx_logo))); -} - -EditorExportPlatformOSX::~EditorExportPlatformOSX() { -} diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h deleted file mode 100644 index ec97d4139f..0000000000 --- a/platform/osx/export/export_plugin.h +++ /dev/null @@ -1,137 +0,0 @@ -/*************************************************************************/ -/*  export_plugin.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 OSX_EXPORT_PLUGIN_H -#define OSX_EXPORT_PLUGIN_H - -#include "core/config/project_settings.h" -#include "core/io/dir_access.h" -#include "core/io/file_access.h" -#include "core/io/marshalls.h" -#include "core/io/resource_saver.h" -#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 <sys/stat.h> - -class EditorExportPlatformOSX : public EditorExportPlatform { -	GDCLASS(EditorExportPlatformOSX, EditorExportPlatform); - -	int version_code = 0; - -	Ref<ImageTexture> logo; - -	void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); -	void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data); - -	Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path); -	Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true); -	Error _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code = true); -	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, -			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); -	void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name); -	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 -	bool use_dmg() const { return true; } -#else -	bool use_dmg() const { return false; } -#endif - -	bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const { -		String pname = p_package; - -		if (pname.length() == 0) { -			if (r_error) { -				*r_error = TTR("Identifier is missing."); -			} -			return false; -		} - -		for (int i = 0; i < pname.length(); i++) { -			char32_t c = pname[i]; -			if (!(is_ascii_alphanumeric_char(c) || c == '-' || c == '.')) { -				if (r_error) { -					*r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c)); -				} -				return false; -			} -		} - -		return true; -	} - -protected: -	virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override; -	virtual void get_export_options(List<ExportOption> *r_options) override; -	virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override; - -public: -	virtual String get_name() const override { return "macOS"; } -	virtual String get_os_name() const override { return "macOS"; } -	virtual Ref<Texture2D> get_logo() const override { return logo; } - -	virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override { -		List<String> list; -		if (use_dmg()) { -			list.push_back("dmg"); -		} -		list.push_back("zip"); -		list.push_back("app"); -		return list; -	} -	virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; - -	virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; - -	virtual void get_platform_features(List<String> *r_features) override { -		r_features->push_back("pc"); -		r_features->push_back("s3tc"); -		r_features->push_back("macos"); -	} - -	virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override { -	} - -	EditorExportPlatformOSX(); -	~EditorExportPlatformOSX(); -}; - -#endif diff --git a/platform/osx/export/lipo.cpp b/platform/osx/export/lipo.cpp deleted file mode 100644 index 82baf18c52..0000000000 --- a/platform/osx/export/lipo.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/*************************************************************************/ -/*  lipo.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 "modules/modules_enabled.gen.h" // For regex. - -#include "lipo.h" - -#ifdef MODULE_REGEX_ENABLED - -bool LipO::is_lipo(const String &p_path) { -	Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); -	ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path)); -	uint32_t magic = fb->get_32(); -	return (magic == 0xbebafeca || magic == 0xcafebabe || magic == 0xbfbafeca || magic == 0xcafebabf); -} - -bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_files) { -	close(); - -	fa = FileAccess::open(p_output_path, FileAccess::WRITE); -	ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_output_path)); - -	uint64_t max_size = 0; -	for (int i = 0; i < p_files.size(); i++) { -		MachO mh; -		if (!mh.open_file(p_files[i])) { -			ERR_FAIL_V_MSG(false, vformat("LipO: Invalid MachO file: \"%s.\"", p_files[i])); -		} - -		FatArch arch; -		arch.cputype = mh.get_cputype(); -		arch.cpusubtype = mh.get_cpusubtype(); -		arch.offset = 0; -		arch.size = mh.get_size(); -		arch.align = mh.get_align(); -		max_size += arch.size; - -		archs.push_back(arch); - -		Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ); -		if (fb.is_null()) { -			close(); -			ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s.\"", p_files[i])); -		} -	} - -	// Write header. -	bool is_64 = (max_size >= std::numeric_limits<uint32_t>::max()); -	if (is_64) { -		fa->store_32(0xbfbafeca); -	} else { -		fa->store_32(0xbebafeca); -	} -	fa->store_32(BSWAP32(archs.size())); -	uint64_t offset = archs.size() * (is_64 ? 32 : 20) + 8; -	for (int i = 0; i < archs.size(); i++) { -		archs.write[i].offset = offset + PAD(offset, uint64_t(1) << archs[i].align); -		if (is_64) { -			fa->store_32(BSWAP32(archs[i].cputype)); -			fa->store_32(BSWAP32(archs[i].cpusubtype)); -			fa->store_64(BSWAP64(archs[i].offset)); -			fa->store_64(BSWAP64(archs[i].size)); -			fa->store_32(BSWAP32(archs[i].align)); -			fa->store_32(0); -		} else { -			fa->store_32(BSWAP32(archs[i].cputype)); -			fa->store_32(BSWAP32(archs[i].cpusubtype)); -			fa->store_32(BSWAP32(archs[i].offset)); -			fa->store_32(BSWAP32(archs[i].size)); -			fa->store_32(BSWAP32(archs[i].align)); -		} -		offset = archs[i].offset + archs[i].size; -	} - -	// Write files and padding. -	for (int i = 0; i < archs.size(); i++) { -		Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ); -		if (fb.is_null()) { -			close(); -			ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s.\"", p_files[i])); -		} -		uint64_t cur = fa->get_position(); -		for (uint64_t j = cur; j < archs[i].offset; j++) { -			fa->store_8(0); -		} -		int pages = archs[i].size / 4096; -		int remain = archs[i].size % 4096; -		unsigned char step[4096]; -		for (int j = 0; j < pages; j++) { -			uint64_t br = fb->get_buffer(step, 4096); -			if (br > 0) { -				fa->store_buffer(step, br); -			} -		} -		uint64_t br = fb->get_buffer(step, remain); -		if (br > 0) { -			fa->store_buffer(step, br); -		} -	} -	return true; -} - -bool LipO::open_file(const String &p_path) { -	close(); - -	fa = FileAccess::open(p_path, FileAccess::READ); -	ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path)); - -	uint32_t magic = fa->get_32(); -	if (magic == 0xbebafeca) { -		// 32-bit fat binary, bswap. -		uint32_t nfat_arch = BSWAP32(fa->get_32()); -		for (uint32_t i = 0; i < nfat_arch; i++) { -			FatArch arch; -			arch.cputype = BSWAP32(fa->get_32()); -			arch.cpusubtype = BSWAP32(fa->get_32()); -			arch.offset = BSWAP32(fa->get_32()); -			arch.size = BSWAP32(fa->get_32()); -			arch.align = BSWAP32(fa->get_32()); - -			archs.push_back(arch); -		} -	} else if (magic == 0xcafebabe) { -		// 32-bit fat binary. -		uint32_t nfat_arch = fa->get_32(); -		for (uint32_t i = 0; i < nfat_arch; i++) { -			FatArch arch; -			arch.cputype = fa->get_32(); -			arch.cpusubtype = fa->get_32(); -			arch.offset = fa->get_32(); -			arch.size = fa->get_32(); -			arch.align = fa->get_32(); - -			archs.push_back(arch); -		} -	} else if (magic == 0xbfbafeca) { -		// 64-bit fat binary, bswap. -		uint32_t nfat_arch = BSWAP32(fa->get_32()); -		for (uint32_t i = 0; i < nfat_arch; i++) { -			FatArch arch; -			arch.cputype = BSWAP32(fa->get_32()); -			arch.cpusubtype = BSWAP32(fa->get_32()); -			arch.offset = BSWAP64(fa->get_64()); -			arch.size = BSWAP64(fa->get_64()); -			arch.align = BSWAP32(fa->get_32()); -			fa->get_32(); // Skip, reserved. - -			archs.push_back(arch); -		} -	} else if (magic == 0xcafebabf) { -		// 64-bit fat binary. -		uint32_t nfat_arch = fa->get_32(); -		for (uint32_t i = 0; i < nfat_arch; i++) { -			FatArch arch; -			arch.cputype = fa->get_32(); -			arch.cpusubtype = fa->get_32(); -			arch.offset = fa->get_64(); -			arch.size = fa->get_64(); -			arch.align = fa->get_32(); -			fa->get_32(); // Skip, reserved. - -			archs.push_back(arch); -		} -	} else { -		close(); -		ERR_FAIL_V_MSG(false, vformat("LipO: Invalid fat binary: \"%s\".", p_path)); -	} -	return true; -} - -int LipO::get_arch_count() const { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened."); -	return archs.size(); -} - -bool LipO::extract_arch(int p_index, const String &p_path) { -	ERR_FAIL_COND_V_MSG(fa.is_null(), false, "LipO: File not opened."); -	ERR_FAIL_INDEX_V(p_index, archs.size(), false); - -	Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::WRITE); -	ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path)); - -	fa->seek(archs[p_index].offset); - -	int pages = archs[p_index].size / 4096; -	int remain = archs[p_index].size % 4096; -	unsigned char step[4096]; -	for (int i = 0; i < pages; i++) { -		uint64_t br = fa->get_buffer(step, 4096); -		if (br > 0) { -			fb->store_buffer(step, br); -		} -	} -	uint64_t br = fa->get_buffer(step, remain); -	if (br > 0) { -		fb->store_buffer(step, br); -	} -	return true; -} - -void LipO::close() { -	archs.clear(); -} - -LipO::~LipO() { -	close(); -} - -#endif // MODULE_REGEX_ENABLED diff --git a/platform/osx/export/lipo.h b/platform/osx/export/lipo.h deleted file mode 100644 index 0e419be17e..0000000000 --- a/platform/osx/export/lipo.h +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************/ -/*  lipo.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.                */ -/*************************************************************************/ - -// Universal / Universal 2 fat binary file creator and extractor. - -#ifndef LIPO_H -#define LIPO_H - -#include "core/io/file_access.h" -#include "core/object/ref_counted.h" -#include "modules/modules_enabled.gen.h" // For regex. - -#include "macho.h" - -#ifdef MODULE_REGEX_ENABLED - -class LipO : public RefCounted { -	struct FatArch { -		uint32_t cputype; -		uint32_t cpusubtype; -		uint64_t offset; -		uint64_t size; -		uint32_t align; -	}; - -	Ref<FileAccess> fa; -	Vector<FatArch> archs; - -	static inline size_t PAD(size_t s, size_t a) { -		return (a - s % a); -	} - -public: -	static bool is_lipo(const String &p_path); - -	bool create_file(const String &p_output_path, const PackedStringArray &p_files); - -	bool open_file(const String &p_path); -	int get_arch_count() const; -	bool extract_arch(int p_index, const String &p_path); - -	void close(); - -	~LipO(); -}; - -#endif // MODULE_REGEX_ENABLED - -#endif // LIPO_H diff --git a/platform/osx/export/macho.cpp b/platform/osx/export/macho.cpp deleted file mode 100644 index e6e67eff06..0000000000 --- a/platform/osx/export/macho.cpp +++ /dev/null @@ -1,548 +0,0 @@ -/*************************************************************************/ -/*  macho.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 "modules/modules_enabled.gen.h" // For regex. - -#include "macho.h" - -#ifdef MODULE_REGEX_ENABLED - -uint32_t MachO::seg_align(uint64_t p_vmaddr, uint32_t p_min, uint32_t p_max) { -	uint32_t align = p_max; -	if (p_vmaddr != 0) { -		uint64_t seg_align = 1; -		align = 0; -		while ((seg_align & p_vmaddr) == 0) { -			seg_align = seg_align << 1; -			align++; -		} -		align = CLAMP(align, p_min, p_max); -	} -	return align; -} - -bool MachO::alloc_signature(uint64_t p_size) { -	ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened."); -	if (signature_offset != 0) { -		// Nothing to do, already have signature load command. -		return true; -	} -	if (lc_limit == 0 || lc_limit + 16 > exe_base) { -		ERR_FAIL_V_MSG(false, "MachO: Can't allocate signature load command, please use \"codesign_allocate\" utility first."); -	} else { -		// Add signature load command. -		signature_offset = lc_limit; - -		fa->seek(lc_limit); -		LoadCommandHeader lc; -		lc.cmd = LC_CODE_SIGNATURE; -		lc.cmdsize = 16; -		if (swap) { -			lc.cmdsize = BSWAP32(lc.cmdsize); -		} -		fa->store_buffer((const uint8_t *)&lc, sizeof(LoadCommandHeader)); - -		uint32_t lc_offset = fa->get_length() + PAD(fa->get_length(), 16); -		uint32_t lc_size = 0; -		if (swap) { -			lc_offset = BSWAP32(lc_offset); -			lc_size = BSWAP32(lc_size); -		} -		fa->store_32(lc_offset); -		fa->store_32(lc_size); - -		// Write new command number. -		fa->seek(0x10); -		uint32_t ncmds = fa->get_32(); -		uint32_t cmdssize = fa->get_32(); -		if (swap) { -			ncmds = BSWAP32(ncmds); -			cmdssize = BSWAP32(cmdssize); -		} -		ncmds += 1; -		cmdssize += 16; -		if (swap) { -			ncmds = BSWAP32(ncmds); -			cmdssize = BSWAP32(cmdssize); -		} -		fa->seek(0x10); -		fa->store_32(ncmds); -		fa->store_32(cmdssize); - -		lc_limit = lc_limit + sizeof(LoadCommandHeader) + 8; - -		return true; -	} -} - -bool MachO::is_macho(const String &p_path) { -	Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); -	ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path)); -	uint32_t magic = fb->get_32(); -	return (magic == 0xcefaedfe || magic == 0xfeedface || magic == 0xcffaedfe || magic == 0xfeedfacf); -} - -bool MachO::open_file(const String &p_path) { -	fa = FileAccess::open(p_path, FileAccess::READ_WRITE); -	ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path)); -	uint32_t magic = fa->get_32(); -	MachHeader mach_header; - -	// Read MachO header. -	swap = (magic == 0xcffaedfe || magic == 0xcefaedfe); -	if (magic == 0xcefaedfe || magic == 0xfeedface) { -		// Thin 32-bit binary. -		fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader)); -	} else if (magic == 0xcffaedfe || magic == 0xfeedfacf) { -		// Thin 64-bit binary. -		fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader)); -		fa->get_32(); // Skip extra reserved field. -	} else { -		ERR_FAIL_V_MSG(false, vformat("MachO: File is not a valid MachO binary: \"%s\".", p_path)); -	} - -	if (swap) { -		mach_header.ncmds = BSWAP32(mach_header.ncmds); -		mach_header.cpusubtype = BSWAP32(mach_header.cpusubtype); -		mach_header.cputype = BSWAP32(mach_header.cputype); -	} -	cpusubtype = mach_header.cpusubtype; -	cputype = mach_header.cputype; -	align = 0; -	exe_base = std::numeric_limits<uint64_t>::max(); -	exe_limit = 0; -	lc_limit = 0; -	link_edit_offset = 0; -	signature_offset = 0; - -	// Read load commands. -	for (uint32_t i = 0; i < mach_header.ncmds; i++) { -		LoadCommandHeader lc; -		fa->get_buffer((uint8_t *)&lc, sizeof(LoadCommandHeader)); -		if (swap) { -			lc.cmd = BSWAP32(lc.cmd); -			lc.cmdsize = BSWAP32(lc.cmdsize); -		} -		uint64_t ps = fa->get_position(); -		switch (lc.cmd) { -			case LC_SEGMENT: { -				LoadCommandSegment lc_seg; -				fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment)); -				if (swap) { -					lc_seg.nsects = BSWAP32(lc_seg.nsects); -					lc_seg.vmaddr = BSWAP32(lc_seg.vmaddr); -					lc_seg.vmsize = BSWAP32(lc_seg.vmsize); -				} -				align = MAX(align, seg_align(lc_seg.vmaddr, 2, 15)); -				if (String(lc_seg.segname) == "__TEXT") { -					exe_limit = MAX(exe_limit, lc_seg.vmsize); -					for (uint32_t j = 0; j < lc_seg.nsects; j++) { -						Section lc_sect; -						fa->get_buffer((uint8_t *)&lc_sect, sizeof(Section)); -						if (String(lc_sect.sectname) == "__text") { -							if (swap) { -								exe_base = MIN(exe_base, BSWAP32(lc_sect.offset)); -							} else { -								exe_base = MIN(exe_base, lc_sect.offset); -							} -						} -						if (swap) { -							align = MAX(align, BSWAP32(lc_sect.align)); -						} else { -							align = MAX(align, lc_sect.align); -						} -					} -				} else if (String(lc_seg.segname) == "__LINKEDIT") { -					link_edit_offset = ps - 8; -				} -			} break; -			case LC_SEGMENT_64: { -				LoadCommandSegment64 lc_seg; -				fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment64)); -				if (swap) { -					lc_seg.nsects = BSWAP32(lc_seg.nsects); -					lc_seg.vmaddr = BSWAP64(lc_seg.vmaddr); -					lc_seg.vmsize = BSWAP64(lc_seg.vmsize); -				} -				align = MAX(align, seg_align(lc_seg.vmaddr, 3, 15)); -				if (String(lc_seg.segname) == "__TEXT") { -					exe_limit = MAX(exe_limit, lc_seg.vmsize); -					for (uint32_t j = 0; j < lc_seg.nsects; j++) { -						Section64 lc_sect; -						fa->get_buffer((uint8_t *)&lc_sect, sizeof(Section64)); -						if (String(lc_sect.sectname) == "__text") { -							if (swap) { -								exe_base = MIN(exe_base, BSWAP32(lc_sect.offset)); -							} else { -								exe_base = MIN(exe_base, lc_sect.offset); -							} -							if (swap) { -								align = MAX(align, BSWAP32(lc_sect.align)); -							} else { -								align = MAX(align, lc_sect.align); -							} -						} -					} -				} else if (String(lc_seg.segname) == "__LINKEDIT") { -					link_edit_offset = ps - 8; -				} -			} break; -			case LC_CODE_SIGNATURE: { -				signature_offset = ps - 8; -			} break; -			default: { -			} break; -		} -		fa->seek(ps + lc.cmdsize - 8); -		lc_limit = ps + lc.cmdsize - 8; -	} - -	if (exe_limit == 0 || lc_limit == 0) { -		ERR_FAIL_V_MSG(false, vformat("MachO: No load commands or executable code found: \"%s\".", p_path)); -	} - -	return true; -} - -uint64_t MachO::get_exe_base() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); -	return exe_base; -} - -uint64_t MachO::get_exe_limit() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); -	return exe_limit; -} - -int32_t MachO::get_align() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); -	return align; -} - -uint32_t MachO::get_cputype() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); -	return cputype; -} - -uint32_t MachO::get_cpusubtype() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); -	return cpusubtype; -} - -uint64_t MachO::get_size() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); -	return fa->get_length(); -} - -uint64_t MachO::get_signature_offset() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); -	ERR_FAIL_COND_V_MSG(signature_offset == 0, 0, "MachO: No signature load command."); - -	fa->seek(signature_offset + 8); -	if (swap) { -		return BSWAP32(fa->get_32()); -	} else { -		return fa->get_32(); -	} -} - -uint64_t MachO::get_code_limit() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); - -	if (signature_offset == 0) { -		return fa->get_length() + PAD(fa->get_length(), 16); -	} else { -		return get_signature_offset(); -	} -} - -uint64_t MachO::get_signature_size() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); -	ERR_FAIL_COND_V_MSG(signature_offset == 0, 0, "MachO: No signature load command."); - -	fa->seek(signature_offset + 12); -	if (swap) { -		return BSWAP32(fa->get_32()); -	} else { -		return fa->get_32(); -	} -} - -bool MachO::is_signed() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened."); -	if (signature_offset == 0) { -		return false; -	} - -	fa->seek(get_signature_offset()); -	uint32_t magic = BSWAP32(fa->get_32()); -	if (magic != 0xfade0cc0) { -		return false; // No SuperBlob found. -	} -	fa->get_32(); // Skip size field, unused. -	uint32_t count = BSWAP32(fa->get_32()); -	for (uint32_t i = 0; i < count; i++) { -		uint32_t index_type = BSWAP32(fa->get_32()); -		uint32_t offset = BSWAP32(fa->get_32()); -		if (index_type == 0x00000000) { // CodeDirectory index type. -			fa->seek(get_signature_offset() + offset + 12); -			uint32_t flags = BSWAP32(fa->get_32()); -			if (flags & 0x20000) { -				return false; // Found CD, linker-signed. -			} else { -				return true; // Found CD, not linker-signed. -			} -		} -	} -	return false; // No CD found. -} - -PackedByteArray MachO::get_cdhash_sha1() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened."); -	if (signature_offset == 0) { -		return PackedByteArray(); -	} - -	fa->seek(get_signature_offset()); -	uint32_t magic = BSWAP32(fa->get_32()); -	if (magic != 0xfade0cc0) { -		return PackedByteArray(); // No SuperBlob found. -	} -	fa->get_32(); // Skip size field, unused. -	uint32_t count = BSWAP32(fa->get_32()); -	for (uint32_t i = 0; i < count; i++) { -		fa->get_32(); // Index type, skip. -		uint32_t offset = BSWAP32(fa->get_32()); -		uint64_t pos = fa->get_position(); - -		fa->seek(get_signature_offset() + offset); -		uint32_t cdmagic = BSWAP32(fa->get_32()); -		uint32_t cdsize = BSWAP32(fa->get_32()); -		if (cdmagic == 0xfade0c02) { // CodeDirectory. -			fa->seek(get_signature_offset() + offset + 36); -			uint8_t hash_size = fa->get_8(); -			uint8_t hash_type = fa->get_8(); -			if (hash_size == 0x14 && hash_type == 0x01) { /* SHA-1 */ -				PackedByteArray hash; -				hash.resize(0x14); - -				fa->seek(get_signature_offset() + offset); -				PackedByteArray blob; -				blob.resize(cdsize); -				fa->get_buffer(blob.ptrw(), cdsize); - -				CryptoCore::SHA1Context ctx; -				ctx.start(); -				ctx.update(blob.ptr(), blob.size()); -				ctx.finish(hash.ptrw()); - -				return hash; -			} -		} -		fa->seek(pos); -	} -	return PackedByteArray(); -} - -PackedByteArray MachO::get_cdhash_sha256() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened."); -	if (signature_offset == 0) { -		return PackedByteArray(); -	} - -	fa->seek(get_signature_offset()); -	uint32_t magic = BSWAP32(fa->get_32()); -	if (magic != 0xfade0cc0) { -		return PackedByteArray(); // No SuperBlob found. -	} -	fa->get_32(); // Skip size field, unused. -	uint32_t count = BSWAP32(fa->get_32()); -	for (uint32_t i = 0; i < count; i++) { -		fa->get_32(); // Index type, skip. -		uint32_t offset = BSWAP32(fa->get_32()); -		uint64_t pos = fa->get_position(); - -		fa->seek(get_signature_offset() + offset); -		uint32_t cdmagic = BSWAP32(fa->get_32()); -		uint32_t cdsize = BSWAP32(fa->get_32()); -		if (cdmagic == 0xfade0c02) { // CodeDirectory. -			fa->seek(get_signature_offset() + offset + 36); -			uint8_t hash_size = fa->get_8(); -			uint8_t hash_type = fa->get_8(); -			if (hash_size == 0x20 && hash_type == 0x02) { /* SHA-256 */ -				PackedByteArray hash; -				hash.resize(0x20); - -				fa->seek(get_signature_offset() + offset); -				PackedByteArray blob; -				blob.resize(cdsize); -				fa->get_buffer(blob.ptrw(), cdsize); - -				CryptoCore::SHA256Context ctx; -				ctx.start(); -				ctx.update(blob.ptr(), blob.size()); -				ctx.finish(hash.ptrw()); - -				return hash; -			} -		} -		fa->seek(pos); -	} -	return PackedByteArray(); -} - -PackedByteArray MachO::get_requirements() { -	ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened."); -	if (signature_offset == 0) { -		return PackedByteArray(); -	} - -	fa->seek(get_signature_offset()); -	uint32_t magic = BSWAP32(fa->get_32()); -	if (magic != 0xfade0cc0) { -		return PackedByteArray(); // No SuperBlob found. -	} -	fa->get_32(); // Skip size field, unused. -	uint32_t count = BSWAP32(fa->get_32()); -	for (uint32_t i = 0; i < count; i++) { -		fa->get_32(); // Index type, skip. -		uint32_t offset = BSWAP32(fa->get_32()); -		uint64_t pos = fa->get_position(); - -		fa->seek(get_signature_offset() + offset); -		uint32_t rqmagic = BSWAP32(fa->get_32()); -		uint32_t rqsize = BSWAP32(fa->get_32()); -		if (rqmagic == 0xfade0c01) { // Requirements. -			PackedByteArray blob; -			fa->seek(get_signature_offset() + offset); -			blob.resize(rqsize); -			fa->get_buffer(blob.ptrw(), rqsize); -			return blob; -		} -		fa->seek(pos); -	} -	return PackedByteArray(); -} - -const Ref<FileAccess> MachO::get_file() const { -	return fa; -} - -Ref<FileAccess> MachO::get_file() { -	return fa; -} - -bool MachO::set_signature_size(uint64_t p_size) { -	ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened."); - -	// Ensure signature load command exists. -	ERR_FAIL_COND_V_MSG(link_edit_offset == 0, false, "MachO: No __LINKEDIT segment found."); -	ERR_FAIL_COND_V_MSG(!alloc_signature(p_size), false, "MachO: Can't allocate signature load command."); - -	// Update signature load command. -	uint64_t old_size = get_signature_size(); -	uint64_t new_size = p_size + PAD(p_size, 16384); - -	if (new_size <= old_size) { -		fa->seek(get_signature_offset()); -		for (uint64_t i = 0; i < old_size; i++) { -			fa->store_8(0x00); -		} -		return true; -	} - -	fa->seek(signature_offset + 12); -	if (swap) { -		fa->store_32(BSWAP32(new_size)); -	} else { -		fa->store_32(new_size); -	} - -	uint64_t end = get_signature_offset() + new_size; - -	// Update "__LINKEDIT" segment. -	LoadCommandHeader lc; -	fa->seek(link_edit_offset); -	fa->get_buffer((uint8_t *)&lc, sizeof(LoadCommandHeader)); -	if (swap) { -		lc.cmd = BSWAP32(lc.cmd); -		lc.cmdsize = BSWAP32(lc.cmdsize); -	} -	switch (lc.cmd) { -		case LC_SEGMENT: { -			LoadCommandSegment lc_seg; -			fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment)); -			if (swap) { -				lc_seg.vmsize = BSWAP32(lc_seg.vmsize); -				lc_seg.filesize = BSWAP32(lc_seg.filesize); -				lc_seg.fileoff = BSWAP32(lc_seg.fileoff); -			} - -			lc_seg.vmsize = end - lc_seg.fileoff; -			lc_seg.vmsize += PAD(lc_seg.vmsize, 4096); -			lc_seg.filesize = end - lc_seg.fileoff; - -			if (swap) { -				lc_seg.vmsize = BSWAP32(lc_seg.vmsize); -				lc_seg.filesize = BSWAP32(lc_seg.filesize); -			} -			fa->seek(link_edit_offset + 8); -			fa->store_buffer((const uint8_t *)&lc_seg, sizeof(LoadCommandSegment)); -		} break; -		case LC_SEGMENT_64: { -			LoadCommandSegment64 lc_seg; -			fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment64)); -			if (swap) { -				lc_seg.vmsize = BSWAP64(lc_seg.vmsize); -				lc_seg.filesize = BSWAP64(lc_seg.filesize); -				lc_seg.fileoff = BSWAP64(lc_seg.fileoff); -			} -			lc_seg.vmsize = end - lc_seg.fileoff; -			lc_seg.vmsize += PAD(lc_seg.vmsize, 4096); -			lc_seg.filesize = end - lc_seg.fileoff; -			if (swap) { -				lc_seg.vmsize = BSWAP64(lc_seg.vmsize); -				lc_seg.filesize = BSWAP64(lc_seg.filesize); -			} -			fa->seek(link_edit_offset + 8); -			fa->store_buffer((const uint8_t *)&lc_seg, sizeof(LoadCommandSegment64)); -		} break; -		default: { -			ERR_FAIL_V_MSG(false, "MachO: Invalid __LINKEDIT segment type."); -		} break; -	} -	fa->seek(get_signature_offset()); -	for (uint64_t i = 0; i < new_size; i++) { -		fa->store_8(0x00); -	} -	return true; -} - -#endif // MODULE_REGEX_ENABLED diff --git a/platform/osx/export/macho.h b/platform/osx/export/macho.h deleted file mode 100644 index 6cfc3c44f5..0000000000 --- a/platform/osx/export/macho.h +++ /dev/null @@ -1,215 +0,0 @@ -/*************************************************************************/ -/*  macho.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.                */ -/*************************************************************************/ - -// Mach-O binary object file format parser and editor. - -#ifndef MACHO_H -#define MACHO_H - -#include "core/crypto/crypto.h" -#include "core/crypto/crypto_core.h" -#include "core/io/file_access.h" -#include "core/object/ref_counted.h" -#include "modules/modules_enabled.gen.h" // For regex. - -#ifdef MODULE_REGEX_ENABLED - -class MachO : public RefCounted { -	struct MachHeader { -		uint32_t cputype; -		uint32_t cpusubtype; -		uint32_t filetype; -		uint32_t ncmds; -		uint32_t sizeofcmds; -		uint32_t flags; -	}; - -	enum LoadCommandID { -		LC_SEGMENT = 0x00000001, -		LC_SYMTAB = 0x00000002, -		LC_SYMSEG = 0x00000003, -		LC_THREAD = 0x00000004, -		LC_UNIXTHREAD = 0x00000005, -		LC_LOADFVMLIB = 0x00000006, -		LC_IDFVMLIB = 0x00000007, -		LC_IDENT = 0x00000008, -		LC_FVMFILE = 0x00000009, -		LC_PREPAGE = 0x0000000a, -		LC_DYSYMTAB = 0x0000000b, -		LC_LOAD_DYLIB = 0x0000000c, -		LC_ID_DYLIB = 0x0000000d, -		LC_LOAD_DYLINKER = 0x0000000e, -		LC_ID_DYLINKER = 0x0000000f, -		LC_PREBOUND_DYLIB = 0x00000010, -		LC_ROUTINES = 0x00000011, -		LC_SUB_FRAMEWORK = 0x00000012, -		LC_SUB_UMBRELLA = 0x00000013, -		LC_SUB_CLIENT = 0x00000014, -		LC_SUB_LIBRARY = 0x00000015, -		LC_TWOLEVEL_HINTS = 0x00000016, -		LC_PREBIND_CKSUM = 0x00000017, -		LC_LOAD_WEAK_DYLIB = 0x80000018, -		LC_SEGMENT_64 = 0x00000019, -		LC_ROUTINES_64 = 0x0000001a, -		LC_UUID = 0x0000001b, -		LC_RPATH = 0x8000001c, -		LC_CODE_SIGNATURE = 0x0000001d, -		LC_SEGMENT_SPLIT_INFO = 0x0000001e, -		LC_REEXPORT_DYLIB = 0x8000001f, -		LC_LAZY_LOAD_DYLIB = 0x00000020, -		LC_ENCRYPTION_INFO = 0x00000021, -		LC_DYLD_INFO = 0x00000022, -		LC_DYLD_INFO_ONLY = 0x80000022, -		LC_LOAD_UPWARD_DYLIB = 0x80000023, -		LC_VERSION_MIN_MACOSX = 0x00000024, -		LC_VERSION_MIN_IPHONEOS = 0x00000025, -		LC_FUNCTION_STARTS = 0x00000026, -		LC_DYLD_ENVIRONMENT = 0x00000027, -		LC_MAIN = 0x80000028, -		LC_DATA_IN_CODE = 0x00000029, -		LC_SOURCE_VERSION = 0x0000002a, -		LC_DYLIB_CODE_SIGN_DRS = 0x0000002b, -		LC_ENCRYPTION_INFO_64 = 0x0000002c, -		LC_LINKER_OPTION = 0x0000002d, -		LC_LINKER_OPTIMIZATION_HINT = 0x0000002e, -		LC_VERSION_MIN_TVOS = 0x0000002f, -		LC_VERSION_MIN_WATCHOS = 0x00000030, -	}; - -	struct LoadCommandHeader { -		uint32_t cmd; -		uint32_t cmdsize; -	}; - -	struct LoadCommandSegment { -		char segname[16]; -		uint32_t vmaddr; -		uint32_t vmsize; -		uint32_t fileoff; -		uint32_t filesize; -		uint32_t maxprot; -		uint32_t initprot; -		uint32_t nsects; -		uint32_t flags; -	}; - -	struct LoadCommandSegment64 { -		char segname[16]; -		uint64_t vmaddr; -		uint64_t vmsize; -		uint64_t fileoff; -		uint64_t filesize; -		uint32_t maxprot; -		uint32_t initprot; -		uint32_t nsects; -		uint32_t flags; -	}; - -	struct Section { -		char sectname[16]; -		char segname[16]; -		uint32_t addr; -		uint32_t size; -		uint32_t offset; -		uint32_t align; -		uint32_t reloff; -		uint32_t nreloc; -		uint32_t flags; -		uint32_t reserved1; -		uint32_t reserved2; -	}; - -	struct Section64 { -		char sectname[16]; -		char segname[16]; -		uint64_t addr; -		uint64_t size; -		uint32_t offset; -		uint32_t align; -		uint32_t reloff; -		uint32_t nreloc; -		uint32_t flags; -		uint32_t reserved1; -		uint32_t reserved2; -		uint32_t reserved3; -	}; - -	Ref<FileAccess> fa; -	bool swap = false; - -	uint64_t lc_limit = 0; - -	uint64_t exe_limit = 0; -	uint64_t exe_base = std::numeric_limits<uint64_t>::max(); // Start of first __text section. -	uint32_t align = 0; -	uint32_t cputype = 0; -	uint32_t cpusubtype = 0; - -	uint64_t link_edit_offset = 0; // __LINKEDIT segment offset. -	uint64_t signature_offset = 0; // Load command offset. - -	uint32_t seg_align(uint64_t p_vmaddr, uint32_t p_min, uint32_t p_max); -	bool alloc_signature(uint64_t p_size); - -	static inline size_t PAD(size_t s, size_t a) { -		return (a - s % a); -	} - -public: -	static bool is_macho(const String &p_path); - -	bool open_file(const String &p_path); - -	uint64_t get_exe_base(); -	uint64_t get_exe_limit(); -	int32_t get_align(); -	uint32_t get_cputype(); -	uint32_t get_cpusubtype(); -	uint64_t get_size(); -	uint64_t get_code_limit(); - -	uint64_t get_signature_offset(); -	bool is_signed(); - -	PackedByteArray get_cdhash_sha1(); -	PackedByteArray get_cdhash_sha256(); - -	PackedByteArray get_requirements(); - -	const Ref<FileAccess> get_file() const; -	Ref<FileAccess> get_file(); - -	uint64_t get_signature_size(); -	bool set_signature_size(uint64_t p_size); -}; - -#endif // MODULE_REGEX_ENABLED - -#endif // MACHO_H diff --git a/platform/osx/export/plist.cpp b/platform/osx/export/plist.cpp deleted file mode 100644 index 36de9dd34b..0000000000 --- a/platform/osx/export/plist.cpp +++ /dev/null @@ -1,570 +0,0 @@ -/*************************************************************************/ -/*  plist.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 "modules/modules_enabled.gen.h" // For regex. - -#include "plist.h" - -#ifdef MODULE_REGEX_ENABLED - -Ref<PListNode> PListNode::new_array() { -	Ref<PListNode> node = memnew(PListNode()); -	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>()); -	node->data_type = PList::PLNodeType::PL_NODE_TYPE_ARRAY; -	return node; -} - -Ref<PListNode> PListNode::new_dict() { -	Ref<PListNode> node = memnew(PListNode()); -	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>()); -	node->data_type = PList::PLNodeType::PL_NODE_TYPE_DICT; -	return node; -} - -Ref<PListNode> PListNode::new_string(const String &p_string) { -	Ref<PListNode> node = memnew(PListNode()); -	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>()); -	node->data_type = PList::PLNodeType::PL_NODE_TYPE_STRING; -	node->data_string = p_string.utf8(); -	return node; -} - -Ref<PListNode> PListNode::new_data(const String &p_string) { -	Ref<PListNode> node = memnew(PListNode()); -	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>()); -	node->data_type = PList::PLNodeType::PL_NODE_TYPE_DATA; -	node->data_string = p_string.utf8(); -	return node; -} - -Ref<PListNode> PListNode::new_date(const String &p_string) { -	Ref<PListNode> node = memnew(PListNode()); -	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>()); -	node->data_type = PList::PLNodeType::PL_NODE_TYPE_DATE; -	node->data_string = p_string.utf8(); -	return node; -} - -Ref<PListNode> PListNode::new_bool(bool p_bool) { -	Ref<PListNode> node = memnew(PListNode()); -	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>()); -	node->data_type = PList::PLNodeType::PL_NODE_TYPE_BOOLEAN; -	node->data_bool = p_bool; -	return node; -} - -Ref<PListNode> PListNode::new_int(int32_t p_int) { -	Ref<PListNode> node = memnew(PListNode()); -	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>()); -	node->data_type = PList::PLNodeType::PL_NODE_TYPE_INTEGER; -	node->data_int = p_int; -	return node; -} - -Ref<PListNode> PListNode::new_real(float p_real) { -	Ref<PListNode> node = memnew(PListNode()); -	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>()); -	node->data_type = PList::PLNodeType::PL_NODE_TYPE_REAL; -	node->data_real = p_real; -	return node; -} - -bool PListNode::push_subnode(const Ref<PListNode> &p_node, const String &p_key) { -	ERR_FAIL_COND_V(p_node.is_null(), false); -	if (data_type == PList::PLNodeType::PL_NODE_TYPE_DICT) { -		ERR_FAIL_COND_V(p_key.is_empty(), false); -		ERR_FAIL_COND_V(data_dict.has(p_key), false); -		data_dict[p_key] = p_node; -		return true; -	} else if (data_type == PList::PLNodeType::PL_NODE_TYPE_ARRAY) { -		data_array.push_back(p_node); -		return true; -	} else { -		ERR_FAIL_V_MSG(false, "PList: Invalid parent node type, should be DICT or ARRAY."); -	} -} - -size_t PListNode::get_asn1_size(uint8_t p_len_octets) const { -	// Get size of all data, excluding type and size information. -	switch (data_type) { -		case PList::PLNodeType::PL_NODE_TYPE_NIL: { -			return 0; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_DATA: -		case PList::PLNodeType::PL_NODE_TYPE_DATE: { -			ERR_FAIL_V_MSG(0, "PList: DATE and DATA nodes are not supported by ASN.1 serialization."); -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_STRING: { -			return data_string.length(); -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_BOOLEAN: { -			return 1; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_INTEGER: -		case PList::PLNodeType::PL_NODE_TYPE_REAL: { -			return 4; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_ARRAY: { -			size_t size = 0; -			for (int i = 0; i < data_array.size(); i++) { -				size += 1 + _asn1_size_len(p_len_octets) + data_array[i]->get_asn1_size(p_len_octets); -			} -			return size; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_DICT: { -			size_t size = 0; - -			for (const KeyValue<String, Ref<PListNode>> &E : data_dict) { -				size += 1 + _asn1_size_len(p_len_octets); // Sequence. -				size += 1 + _asn1_size_len(p_len_octets) + E.key.utf8().length(); //Key. -				size += 1 + _asn1_size_len(p_len_octets) + E.value->get_asn1_size(p_len_octets); // Value. -			} -			return size; -		} break; -		default: { -			return 0; -		} break; -	} -} - -int PListNode::_asn1_size_len(uint8_t p_len_octets) { -	if (p_len_octets > 1) { -		return p_len_octets + 1; -	} else { -		return 1; -	} -} - -void PListNode::store_asn1_size(PackedByteArray &p_stream, uint8_t p_len_octets) const { -	uint32_t size = get_asn1_size(p_len_octets); -	if (p_len_octets > 1) { -		p_stream.push_back(0x80 + p_len_octets); -	} -	for (int i = p_len_octets - 1; i >= 0; i--) { -		uint8_t x = (size >> i * 8) & 0xFF; -		p_stream.push_back(x); -	} -} - -bool PListNode::store_asn1(PackedByteArray &p_stream, uint8_t p_len_octets) const { -	// Convert to binary ASN1 stream. -	bool valid = true; -	switch (data_type) { -		case PList::PLNodeType::PL_NODE_TYPE_NIL: { -			// Nothing to store. -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_DATE: -		case PList::PLNodeType::PL_NODE_TYPE_DATA: { -			ERR_FAIL_V_MSG(false, "PList: DATE and DATA nodes are not supported by ASN.1 serialization."); -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_STRING: { -			p_stream.push_back(0x0C); -			store_asn1_size(p_stream, p_len_octets); -			for (int i = 0; i < data_string.size(); i++) { -				p_stream.push_back(data_string[i]); -			} -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_BOOLEAN: { -			p_stream.push_back(0x01); -			store_asn1_size(p_stream, p_len_octets); -			if (data_bool) { -				p_stream.push_back(0x01); -			} else { -				p_stream.push_back(0x00); -			} -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_INTEGER: { -			p_stream.push_back(0x02); -			store_asn1_size(p_stream, p_len_octets); -			for (int i = 4; i >= 0; i--) { -				uint8_t x = (data_int >> i * 8) & 0xFF; -				p_stream.push_back(x); -			} -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_REAL: { -			p_stream.push_back(0x03); -			store_asn1_size(p_stream, p_len_octets); -			for (int i = 4; i >= 0; i--) { -				uint8_t x = (data_int >> i * 8) & 0xFF; -				p_stream.push_back(x); -			} -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_ARRAY: { -			p_stream.push_back(0x30); // Sequence. -			store_asn1_size(p_stream, p_len_octets); -			for (int i = 0; i < data_array.size(); i++) { -				valid = valid && data_array[i]->store_asn1(p_stream, p_len_octets); -			} -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_DICT: { -			p_stream.push_back(0x31); // Set. -			store_asn1_size(p_stream, p_len_octets); -			for (const KeyValue<String, Ref<PListNode>> &E : data_dict) { -				CharString cs = E.key.utf8(); -				uint32_t size = cs.length(); - -				// Sequence. -				p_stream.push_back(0x30); -				uint32_t seq_size = 2 * (1 + _asn1_size_len(p_len_octets)) + size + E.value->get_asn1_size(p_len_octets); -				if (p_len_octets > 1) { -					p_stream.push_back(0x80 + p_len_octets); -				} -				for (int i = p_len_octets - 1; i >= 0; i--) { -					uint8_t x = (seq_size >> i * 8) & 0xFF; -					p_stream.push_back(x); -				} -				// Key. -				p_stream.push_back(0x0C); -				if (p_len_octets > 1) { -					p_stream.push_back(0x80 + p_len_octets); -				} -				for (int i = p_len_octets - 1; i >= 0; i--) { -					uint8_t x = (size >> i * 8) & 0xFF; -					p_stream.push_back(x); -				} -				for (uint32_t i = 0; i < size; i++) { -					p_stream.push_back(cs[i]); -				} -				// Value. -				valid = valid && E.value->store_asn1(p_stream, p_len_octets); -			} -		} break; -	} -	return valid; -} - -void PListNode::store_text(String &p_stream, uint8_t p_indent) const { -	// Convert to text XML stream. -	switch (data_type) { -		case PList::PLNodeType::PL_NODE_TYPE_NIL: { -			// Nothing to store. -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_DATA: { -			p_stream += String("\t").repeat(p_indent); -			p_stream += "<data>\n"; -			p_stream += String("\t").repeat(p_indent); -			p_stream += data_string + "\n"; -			p_stream += String("\t").repeat(p_indent); -			p_stream += "</data>\n"; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_DATE: { -			p_stream += String("\t").repeat(p_indent); -			p_stream += "<date>"; -			p_stream += data_string; -			p_stream += "</date>\n"; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_STRING: { -			p_stream += String("\t").repeat(p_indent); -			p_stream += "<string>"; -			p_stream += String::utf8(data_string); -			p_stream += "</string>\n"; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_BOOLEAN: { -			p_stream += String("\t").repeat(p_indent); -			if (data_bool) { -				p_stream += "<true/>\n"; -			} else { -				p_stream += "<false/>\n"; -			} -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_INTEGER: { -			p_stream += String("\t").repeat(p_indent); -			p_stream += "<integer>"; -			p_stream += itos(data_int); -			p_stream += "</integer>\n"; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_REAL: { -			p_stream += String("\t").repeat(p_indent); -			p_stream += "<real>"; -			p_stream += rtos(data_real); -			p_stream += "</real>\n"; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_ARRAY: { -			p_stream += String("\t").repeat(p_indent); -			p_stream += "<array>\n"; -			for (int i = 0; i < data_array.size(); i++) { -				data_array[i]->store_text(p_stream, p_indent + 1); -			} -			p_stream += String("\t").repeat(p_indent); -			p_stream += "</array>\n"; -		} break; -		case PList::PLNodeType::PL_NODE_TYPE_DICT: { -			p_stream += String("\t").repeat(p_indent); -			p_stream += "<dict>\n"; -			for (const KeyValue<String, Ref<PListNode>> &E : data_dict) { -				p_stream += String("\t").repeat(p_indent + 1); -				p_stream += "<key>"; -				p_stream += E.key; -				p_stream += "</key>\n"; -				E.value->store_text(p_stream, p_indent + 1); -			} -			p_stream += String("\t").repeat(p_indent); -			p_stream += "</dict>\n"; -		} break; -	} -} - -/*************************************************************************/ - -PList::PList() { -	root = PListNode::new_dict(); -} - -PList::PList(const String &p_string) { -	load_string(p_string); -} - -bool PList::load_file(const String &p_filename) { -	root = Ref<PListNode>(); - -	Ref<FileAccess> fb = FileAccess::open(p_filename, FileAccess::READ); -	if (fb.is_null()) { -		return false; -	} - -	unsigned char magic[8]; -	fb->get_buffer(magic, 8); - -	if (String((const char *)magic, 8) == "bplist00") { -		ERR_FAIL_V_MSG(false, "PList: Binary property lists are not supported."); -	} else { -		// Load text plist. -		Error err; -		Vector<uint8_t> array = FileAccess::get_file_as_array(p_filename, &err); -		ERR_FAIL_COND_V(err != OK, false); - -		String ret; -		ret.parse_utf8((const char *)array.ptr(), array.size()); -		return load_string(ret); -	} -} - -bool PList::load_string(const String &p_string) { -	root = Ref<PListNode>(); - -	int pos = 0; -	bool in_plist = false; -	bool done_plist = false; -	List<Ref<PListNode>> stack; -	String key; -	while (pos >= 0) { -		int open_token_s = p_string.find("<", pos); -		if (open_token_s == -1) { -			ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. No tags found."); -		} -		int open_token_e = p_string.find(">", open_token_s); -		pos = open_token_e; - -		String token = p_string.substr(open_token_s + 1, open_token_e - open_token_s - 1); -		if (token.is_empty()) { -			ERR_FAIL_V_MSG(false, "PList: Invalid token name."); -		} -		String value; -		if (token[0] == '?' || token[0] == '!') { // Skip <?xml ... ?> and <!DOCTYPE ... > -			int end_token_e = p_string.find(">", open_token_s); -			pos = end_token_e; -			continue; -		} - -		if (token.find("plist", 0) == 0) { -			in_plist = true; -			continue; -		} - -		if (token == "/plist") { -			done_plist = true; -			break; -		} - -		if (!in_plist) { -			ERR_FAIL_V_MSG(false, "PList: Node outside of <plist> tag."); -		} - -		if (token == "dict") { -			if (!stack.is_empty()) { -				// Add subnode end enter it. -				Ref<PListNode> dict = PListNode::new_dict(); -				dict->data_type = PList::PLNodeType::PL_NODE_TYPE_DICT; -				if (!stack.back()->get()->push_subnode(dict, key)) { -					ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type."); -				} -				stack.push_back(dict); -			} else { -				// Add root node. -				if (!root.is_null()) { -					ERR_FAIL_V_MSG(false, "PList: Root node already set."); -				} -				Ref<PListNode> dict = PListNode::new_dict(); -				stack.push_back(dict); -				root = dict; -			} -			continue; -		} - -		if (token == "/dict") { -			// Exit current dict. -			if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_DICT) { -				ERR_FAIL_V_MSG(false, "PList: Mismatched </dict> tag."); -			} -			stack.pop_back(); -			continue; -		} - -		if (token == "array") { -			if (!stack.is_empty()) { -				// Add subnode end enter it. -				Ref<PListNode> arr = PListNode::new_array(); -				if (!stack.back()->get()->push_subnode(arr, key)) { -					ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type."); -				} -				stack.push_back(arr); -			} else { -				// Add root node. -				if (!root.is_null()) { -					ERR_FAIL_V_MSG(false, "PList: Root node already set."); -				} -				Ref<PListNode> arr = PListNode::new_array(); -				stack.push_back(arr); -				root = arr; -			} -			continue; -		} - -		if (token == "/array") { -			// Exit current array. -			if (stack.is_empty() || stack.back()->get()->data_type != PList::PLNodeType::PL_NODE_TYPE_ARRAY) { -				ERR_FAIL_V_MSG(false, "PList: Mismatched </array> tag."); -			} -			stack.pop_back(); -			continue; -		} - -		if (token[token.length() - 1] == '/') { -			token = token.substr(0, token.length() - 1); -		} else { -			int end_token_s = p_string.find("</", pos); -			if (end_token_s == -1) { -				ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> tag.", token)); -			} -			int end_token_e = p_string.find(">", end_token_s); -			pos = end_token_e; -			String end_token = p_string.substr(end_token_s + 2, end_token_e - end_token_s - 2); -			if (end_token != token) { -				ERR_FAIL_V_MSG(false, vformat("PList: Mismatched <%s> and <%s> token pair.", token, end_token)); -			} -			value = p_string.substr(open_token_e + 1, end_token_s - open_token_e - 1); -		} -		if (token == "key") { -			key = value; -		} else { -			Ref<PListNode> var = nullptr; -			if (token == "true") { -				var = PListNode::new_bool(true); -			} else if (token == "false") { -				var = PListNode::new_bool(false); -			} else if (token == "integer") { -				var = PListNode::new_int(value.to_int()); -			} else if (token == "real") { -				var = PListNode::new_real(value.to_float()); -			} else if (token == "string") { -				var = PListNode::new_string(value); -			} else if (token == "data") { -				var = PListNode::new_data(value); -			} else if (token == "date") { -				var = PListNode::new_date(value); -			} else { -				ERR_FAIL_V_MSG(false, "PList: Invalid value type."); -			} -			if (stack.is_empty() || !stack.back()->get()->push_subnode(var, key)) { -				ERR_FAIL_V_MSG(false, "PList: Can't push subnode, invalid parent type."); -			} -		} -	} -	if (!stack.is_empty() || !done_plist) { -		ERR_FAIL_V_MSG(false, "PList: Unexpected end of data. Root node is not closed."); -	} -	return true; -} - -PackedByteArray PList::save_asn1() const { -	if (root == nullptr) { -		ERR_FAIL_V_MSG(PackedByteArray(), "PList: Invalid PList, no root node."); -	} -	size_t size = root->get_asn1_size(1); -	uint8_t len_octets = 0; -	if (size < 0x80) { -		len_octets = 1; -	} else { -		size = root->get_asn1_size(2); -		if (size < 0xFFFF) { -			len_octets = 2; -		} else { -			size = root->get_asn1_size(3); -			if (size < 0xFFFFFF) { -				len_octets = 3; -			} else { -				size = root->get_asn1_size(4); -				if (size < 0xFFFFFFFF) { -					len_octets = 4; -				} else { -					ERR_FAIL_V_MSG(PackedByteArray(), "PList: Data is too big for ASN.1 serializer, should be < 4 GiB."); -				} -			} -		} -	} - -	PackedByteArray ret; -	if (!root->store_asn1(ret, len_octets)) { -		ERR_FAIL_V_MSG(PackedByteArray(), "PList: ASN.1 serializer error."); -	} -	return ret; -} - -String PList::save_text() const { -	if (root == nullptr) { -		ERR_FAIL_V_MSG(String(), "PList: Invalid PList, no root node."); -	} - -	String ret; -	ret += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; -	ret += "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"; -	ret += "<plist version=\"1.0\">\n"; - -	root->store_text(ret, 0); - -	ret += "</plist>\n\n"; -	return ret; -} - -Ref<PListNode> PList::get_root() { -	return root; -} - -#endif // MODULE_REGEX_ENABLED diff --git a/platform/osx/export/plist.h b/platform/osx/export/plist.h deleted file mode 100644 index ba9eaec196..0000000000 --- a/platform/osx/export/plist.h +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************/ -/*  plist.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.                */ -/*************************************************************************/ - -// Property list file format (application/x-plist) parser, property list ASN-1 serialization. - -#ifndef PLIST_H -#define PLIST_H - -#include "core/crypto/crypto_core.h" -#include "core/io/file_access.h" -#include "modules/modules_enabled.gen.h" // For regex. - -#ifdef MODULE_REGEX_ENABLED - -class PListNode; - -class PList : public RefCounted { -	friend class PListNode; - -public: -	enum PLNodeType { -		PL_NODE_TYPE_NIL, -		PL_NODE_TYPE_STRING, -		PL_NODE_TYPE_ARRAY, -		PL_NODE_TYPE_DICT, -		PL_NODE_TYPE_BOOLEAN, -		PL_NODE_TYPE_INTEGER, -		PL_NODE_TYPE_REAL, -		PL_NODE_TYPE_DATA, -		PL_NODE_TYPE_DATE, -	}; - -private: -	Ref<PListNode> root; - -public: -	PList(); -	PList(const String &p_string); - -	bool load_file(const String &p_filename); -	bool load_string(const String &p_string); - -	PackedByteArray save_asn1() const; -	String save_text() const; - -	Ref<PListNode> get_root(); -}; - -/*************************************************************************/ - -class PListNode : public RefCounted { -	static int _asn1_size_len(uint8_t p_len_octets); - -public: -	PList::PLNodeType data_type = PList::PLNodeType::PL_NODE_TYPE_NIL; - -	CharString data_string; -	Vector<Ref<PListNode>> data_array; -	HashMap<String, Ref<PListNode>> data_dict; -	union { -		int32_t data_int; -		bool data_bool; -		float data_real; -	}; - -	static Ref<PListNode> new_array(); -	static Ref<PListNode> new_dict(); -	static Ref<PListNode> new_string(const String &p_string); -	static Ref<PListNode> new_data(const String &p_string); -	static Ref<PListNode> new_date(const String &p_string); -	static Ref<PListNode> new_bool(bool p_bool); -	static Ref<PListNode> new_int(int32_t p_int); -	static Ref<PListNode> new_real(float p_real); - -	bool push_subnode(const Ref<PListNode> &p_node, const String &p_key = ""); - -	size_t get_asn1_size(uint8_t p_len_octets) const; - -	void store_asn1_size(PackedByteArray &p_stream, uint8_t p_len_octets) const; -	bool store_asn1(PackedByteArray &p_stream, uint8_t p_len_octets) const; -	void store_text(String &p_stream, uint8_t p_indent) const; - -	PListNode() {} -	~PListNode() {} -}; - -#endif // MODULE_REGEX_ENABLED - -#endif // PLIST_H diff --git a/platform/osx/gl_manager_osx_legacy.h b/platform/osx/gl_manager_osx_legacy.h deleted file mode 100644 index 2d4913a7a6..0000000000 --- a/platform/osx/gl_manager_osx_legacy.h +++ /dev/null @@ -1,97 +0,0 @@ -/*************************************************************************/ -/*  gl_manager_osx_legacy.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 GL_MANAGER_OSX_LEGACY_H -#define GL_MANAGER_OSX_LEGACY_H - -#if defined(OSX_ENABLED) && defined(GLES3_ENABLED) - -#include "core/error/error_list.h" -#include "core/os/os.h" -#include "core/templates/local_vector.h" -#include "servers/display_server.h" - -#import <AppKit/AppKit.h> -#import <ApplicationServices/ApplicationServices.h> -#import <CoreVideo/CoreVideo.h> - -class GLManager_OSX { -public: -	enum ContextType { -		GLES_3_0_COMPATIBLE, -	}; - -private: -	struct GLWindow { -		int width = 0; -		int height = 0; - -		id window_view = nullptr; -		NSOpenGLContext *context = nullptr; -	}; - -	RBMap<DisplayServer::WindowID, GLWindow> windows; - -	NSOpenGLContext *shared_context = nullptr; -	DisplayServer::WindowID current_window = DisplayServer::INVALID_WINDOW_ID; - -	Error create_context(GLWindow &win); - -	bool use_vsync = false; -	ContextType context_type; - -public: -	Error window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height); -	void window_destroy(DisplayServer::WindowID p_window_id); -	void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); - -	int window_get_width(DisplayServer::WindowID p_window_id = 0); -	int window_get_height(DisplayServer::WindowID p_window_id = 0); - -	void release_current(); -	void make_current(); -	void swap_buffers(); - -	void window_make_current(DisplayServer::WindowID p_window_id); - -	void window_update(DisplayServer::WindowID p_window_id); -	void window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled); - -	Error initialize(); - -	void set_use_vsync(bool p_use); -	bool is_using_vsync() const; - -	GLManager_OSX(ContextType p_context_type); -	~GLManager_OSX(); -}; - -#endif // OSX_ENABLED && GLES3_ENABLED -#endif // GL_MANAGER_OSX_LEGACY_H diff --git a/platform/osx/gl_manager_osx_legacy.mm b/platform/osx/gl_manager_osx_legacy.mm deleted file mode 100644 index c769d7f5c5..0000000000 --- a/platform/osx/gl_manager_osx_legacy.mm +++ /dev/null @@ -1,228 +0,0 @@ -/*************************************************************************/ -/*  gl_manager_osx_legacy.mm                                             */ -/*************************************************************************/ -/*                       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 "gl_manager_osx_legacy.h" - -#ifdef OSX_ENABLED -#ifdef GLES3_ENABLED - -#include <stdio.h> -#include <stdlib.h> - -Error GLManager_OSX::create_context(GLWindow &win) { -	NSOpenGLPixelFormatAttribute attributes[] = { -		NSOpenGLPFADoubleBuffer, -		NSOpenGLPFAClosestPolicy, -		NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, -		NSOpenGLPFAColorSize, 32, -		NSOpenGLPFADepthSize, 24, -		NSOpenGLPFAStencilSize, 8, -		0 -	}; - -	NSOpenGLPixelFormat *pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; -	ERR_FAIL_COND_V(pixel_format == nil, ERR_CANT_CREATE); - -	win.context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:shared_context]; -	ERR_FAIL_COND_V(win.context == nil, ERR_CANT_CREATE); -	if (shared_context == nullptr) { -		shared_context = win.context; -	} - -	[win.context setView:win.window_view]; -	[win.context makeCurrentContext]; - -	return OK; -} - -Error GLManager_OSX::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; -	win.window_view = p_view; - -	if (create_context(win) != OK) { -		return FAILED; -	} - -	windows[p_window_id] = win; -	window_make_current(p_window_id); - -	return OK; -} - -void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { -	if (!windows.has(p_window_id)) { -		return; -	} - -	GLWindow &win = windows[p_window_id]; - -	win.width = p_width; -	win.height = p_height; - -	GLint dim[2]; -	dim[0] = p_width; -	dim[1] = p_height; -	CGLSetParameter((CGLContextObj)[win.context CGLContextObj], kCGLCPSurfaceBackingSize, &dim[0]); -	CGLEnable((CGLContextObj)[win.context CGLContextObj], kCGLCESurfaceBackingSize); -	if (OS::get_singleton()->is_hidpi_allowed()) { -		[win.window_view setWantsBestResolutionOpenGLSurface:YES]; -	} else { -		[win.window_view setWantsBestResolutionOpenGLSurface:NO]; -	} - -	[win.context update]; -} - -int GLManager_OSX::window_get_width(DisplayServer::WindowID p_window_id) { -	if (!windows.has(p_window_id)) { -		return 0; -	} - -	GLWindow &win = windows[p_window_id]; -	return win.width; -} - -int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) { -	if (!windows.has(p_window_id)) { -		return 0; -	} - -	GLWindow &win = windows[p_window_id]; -	return win.height; -} - -void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) { -	if (!windows.has(p_window_id)) { -		return; -	} - -	if (current_window == p_window_id) { -		current_window = DisplayServer::INVALID_WINDOW_ID; -	} - -	windows.erase(p_window_id); -} - -void GLManager_OSX::release_current() { -	if (current_window == DisplayServer::INVALID_WINDOW_ID) { -		return; -	} - -	[NSOpenGLContext clearCurrentContext]; -} - -void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) { -	if (current_window == p_window_id) { -		return; -	} -	if (!windows.has(p_window_id)) { -		return; -	} - -	GLWindow &win = windows[p_window_id]; -	[win.context makeCurrentContext]; - -	current_window = p_window_id; -} - -void GLManager_OSX::make_current() { -	if (current_window == DisplayServer::INVALID_WINDOW_ID) { -		return; -	} -	if (!windows.has(current_window)) { -		return; -	} - -	GLWindow &win = windows[current_window]; -	[win.context makeCurrentContext]; -} - -void GLManager_OSX::swap_buffers() { -	for (const KeyValue<DisplayServer::WindowID, GLWindow> &E : windows) { -		[E.value.context flushBuffer]; -	} -} - -void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) { -	if (!windows.has(p_window_id)) { -		return; -	} - -	GLWindow &win = windows[p_window_id]; -	[win.context update]; -} - -void GLManager_OSX::window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled) { -	if (!windows.has(p_window_id)) { -		return; -	} - -	GLWindow &win = windows[p_window_id]; -	if (p_enabled) { -		GLint opacity = 0; -		[win.context setValues:&opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; -	} else { -		GLint opacity = 1; -		[win.context setValues:&opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; -	} -	[win.context update]; -} - -Error GLManager_OSX::initialize() { -	return OK; -} - -void GLManager_OSX::set_use_vsync(bool p_use) { -	use_vsync = p_use; - -	CGLContextObj ctx = CGLGetCurrentContext(); -	if (ctx) { -		GLint swapInterval = p_use ? 1 : 0; -		CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval); -		use_vsync = p_use; -	} -} - -bool GLManager_OSX::is_using_vsync() const { -	return use_vsync; -} - -GLManager_OSX::GLManager_OSX(ContextType p_context_type) { -	context_type = p_context_type; -} - -GLManager_OSX::~GLManager_OSX() { -	release_current(); -} - -#endif // GLES3_ENABLED -#endif // OSX diff --git a/platform/osx/godot_application.h b/platform/osx/godot_application.h deleted file mode 100644 index 8d48a659f3..0000000000 --- a/platform/osx/godot_application.h +++ /dev/null @@ -1,42 +0,0 @@ -/*************************************************************************/ -/*  godot_application.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 GODOT_APPLICATION_H -#define GODOT_APPLICATION_H - -#include "core/os/os.h" - -#import <AppKit/AppKit.h> -#import <Foundation/Foundation.h> - -@interface GodotApplication : NSApplication -@end - -#endif // GODOT_APPLICATION_H diff --git a/platform/osx/godot_application.mm b/platform/osx/godot_application.mm deleted file mode 100644 index 13313a025a..0000000000 --- a/platform/osx/godot_application.mm +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************/ -/*  godot_application.mm                                                 */ -/*************************************************************************/ -/*                       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 "godot_application.h" - -#include "display_server_osx.h" - -@implementation GodotApplication - -- (void)sendEvent:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (ds) { -		if ([event type] == NSEventTypeLeftMouseDown || [event type] == NSEventTypeRightMouseDown || [event type] == NSEventTypeOtherMouseDown) { -			if (ds->mouse_process_popups()) { -				return; -			} -		} -		ds->send_event(event); -	} - -	// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost -	// This works around an AppKit bug, where key up events while holding -	// down the command key don't get sent to the key window. -	if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) { -		[[self keyWindow] sendEvent:event]; -	} else { -		[super sendEvent:event]; -	} -} - -@end diff --git a/platform/osx/godot_application_delegate.h b/platform/osx/godot_application_delegate.h deleted file mode 100644 index f5b67b580f..0000000000 --- a/platform/osx/godot_application_delegate.h +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************/ -/*  godot_application_delegate.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 GODOT_APPLICATION_DELEGATE_H -#define GODOT_APPLICATION_DELEGATE_H - -#include "core/os/os.h" - -#import <AppKit/AppKit.h> -#import <Foundation/Foundation.h> - -@interface GodotApplicationDelegate : NSObject -- (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/osx/godot_application_delegate.mm deleted file mode 100644 index 4d3558b273..0000000000 --- a/platform/osx/godot_application_delegate.mm +++ /dev/null @@ -1,163 +0,0 @@ -/*************************************************************************/ -/*  godot_application_delegate.mm                                        */ -/*************************************************************************/ -/*                       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 "godot_application_delegate.h" - -#include "display_server_osx.h" -#include "os_osx.h" - -@implementation GodotApplicationDelegate - -- (void)forceUnbundledWindowActivationHackStep1 { -	// Step 1: Switch focus to macOS SystemUIServer process. -	// Required to perform step 2, TransformProcessType will fail if app is already the in focus. -	for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.systemuiserver"]) { -		[app activateWithOptions:NSApplicationActivateIgnoringOtherApps]; -		break; -	} -	[self performSelector:@selector(forceUnbundledWindowActivationHackStep2) -			   withObject:nil -			   afterDelay:0.02]; -} - -- (void)forceUnbundledWindowActivationHackStep2 { -	// Step 2: Register app as foreground process. -	ProcessSerialNumber psn = { 0, kCurrentProcess }; -	(void)TransformProcessType(&psn, kProcessTransformToForegroundApplication); -	[self performSelector:@selector(forceUnbundledWindowActivationHackStep3) withObject:nil afterDelay:0.02]; -} - -- (void)forceUnbundledWindowActivationHackStep3 { -	// Step 3: Switch focus back to app window. -	[[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps]; -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notice { -	NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; -	if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO)) { -		// If the executable is started from terminal or is not bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored). -		[self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02]; -	} -} - -- (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_OSX *os = (OS_OSX *)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(); -	if (ds) { -		ds->mouse_process_popups(true); -	} -	if (OS::get_singleton()->get_main_loop()) { -		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); -	} -} - -- (void)applicationDidBecomeActive:(NSNotification *)notification { -	if (OS::get_singleton()->get_main_loop()) { -		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); -	} -} - -- (void)globalMenuCallback:(id)sender { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (ds) { -		return ds->menu_callback(sender); -	} -} - -- (NSMenu *)applicationDockMenu:(NSApplication *)sender { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (ds) { -		return ds->get_dock_menu(); -	} else { -		return nullptr; -	} -} - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (ds) { -		ds->send_window_event(ds->get_window(DisplayServerOSX::MAIN_WINDOW_ID), DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); -	} -	return NSTerminateCancel; -} - -- (void)showAbout:(id)sender { -	OS_OSX *os = (OS_OSX *)OS::get_singleton(); -	if (os && os->get_main_loop()) { -		os->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT); -	} -} - -@end diff --git a/platform/osx/godot_content_view.h b/platform/osx/godot_content_view.h deleted file mode 100644 index 353305aec1..0000000000 --- a/platform/osx/godot_content_view.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************/ -/*  godot_content_view.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 GODOT_CONTENT_VIEW_H -#define GODOT_CONTENT_VIEW_H - -#include "servers/display_server.h" - -#import <AppKit/AppKit.h> -#import <Foundation/Foundation.h> - -#if defined(GLES3_ENABLED) -#import <AppKit/NSOpenGLView.h> -#define RootView NSOpenGLView -#else -#define RootView NSView -#endif - -#import <QuartzCore/CAMetalLayer.h> - -@interface GodotContentView : RootView <NSTextInputClient> { -	DisplayServer::WindowID window_id; -	NSTrackingArea *tracking_area; -	NSMutableAttributedString *marked_text; -	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; -- (void)processPanEvent:(NSEvent *)event dx:(double)dx dy:(double)dy; -- (void)processMouseEvent:(NSEvent *)event index:(MouseButton)index mask:(MouseButton)mask pressed:(bool)pressed; -- (void)setWindowID:(DisplayServer::WindowID)wid; -- (void)cancelComposition; - -@end - -#endif // GODOT_CONTENT_VIEW_H diff --git a/platform/osx/godot_content_view.mm b/platform/osx/godot_content_view.mm deleted file mode 100644 index 018b90e629..0000000000 --- a/platform/osx/godot_content_view.mm +++ /dev/null @@ -1,771 +0,0 @@ -/*************************************************************************/ -/*  godot_content_view.mm                                                */ -/*************************************************************************/ -/*                       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 "godot_content_view.h" - -#include "display_server_osx.h" -#include "key_mapping_osx.h" - -@implementation GodotContentView - -- (id)init { -	self = [super init]; -	window_id = DisplayServer::INVALID_WINDOW_ID; -	tracking_area = nil; -	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, *)) { -		[self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]]; -#if !defined(__aarch64__) // Do not build deprectead 10.13 code on ARM. -	} else { -		[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]]; -#endif -	} -	marked_text = [[NSMutableAttributedString alloc] init]; -	return self; -} - -- (void)setWindowID:(DisplayServerOSX::WindowID)wid { -	window_id = wid; -} - -// MARK: Backing Layer - -- (CALayer *)makeBackingLayer { -	return [[CAMetalLayer class] layer]; -} - -- (void)updateLayer { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	ds->window_update(window_id); -	[super updateLayer]; -} - -- (BOOL)wantsUpdateLayer { -	return YES; -} - -- (BOOL)isOpaque { -	return YES; -} - -// MARK: IME - -- (BOOL)hasMarkedText { -	return (marked_text.length > 0); -} - -- (NSRange)markedRange { -	return NSMakeRange(0, marked_text.length); -} - -- (NSRange)selectedRange { -	static const NSRange kEmptyRange = { NSNotFound, 0 }; -	return kEmptyRange; -} - -- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange { -	if ([aString isKindOfClass:[NSAttributedString class]]) { -		marked_text = [[NSMutableAttributedString alloc] initWithAttributedString:aString]; -	} else { -		marked_text = [[NSMutableAttributedString alloc] initWithString:aString]; -	} -	if (marked_text.length == 0) { -		[self unmarkText]; -		return; -	} - -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::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])); -	} -} - -- (void)doCommandBySelector:(SEL)aSelector { -	[self tryToPerform:aSelector with:self]; -} - -- (void)unmarkText { -	ime_input_event_in_progress = false; -	[[marked_text mutableString] setString:@""]; - -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	if (wd.im_active) { -		ds->update_im_text(Point2i(), String()); -	} -} - -- (NSArray *)validAttributesForMarkedText { -	return [NSArray array]; -} - -- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { -	return nil; -} - -- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint { -	return 0; -} - -- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return NSMakeRect(0, 0, 0, 0); -	} - -	DisplayServerOSX::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); -	NSPoint point_on_screen = [wd.window_object convertRectToScreen:point_in_window_rect].origin; - -	return NSMakeRect(point_on_screen.x, point_on_screen.y, 0, 0); -} - -- (void)cancelComposition { -	[self unmarkText]; -	[[NSTextInputContext currentInputContext] discardMarkedText]; -} - -- (void)insertText:(id)aString { -	[self insertText:aString replacementRange:NSMakeRange(0, 0)]; -} - -- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange { -	NSEvent *event = [NSApp currentEvent]; - -	NSString *characters; -	if ([aString isKindOfClass:[NSAttributedString class]]) { -		characters = [aString string]; -	} else { -		characters = (NSString *)aString; -	} - -	NSCharacterSet *ctrl_chars = [NSCharacterSet controlCharacterSet]; -	NSCharacterSet *wsnl_chars = [NSCharacterSet whitespaceAndNewlineCharacterSet]; -	if ([characters rangeOfCharacterFromSet:ctrl_chars].length && [characters rangeOfCharacterFromSet:wsnl_chars].length == 0) { -		[[NSTextInputContext currentInputContext] discardMarkedText]; -		[self cancelComposition]; -		return; -	} - -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		[self cancelComposition]; -		return; -	} - -	Char16String text; -	text.resize([characters length] + 1); -	[characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])]; - -	String u32text; -	u32text.parse_utf16(text.ptr(), text.length()); - -	for (int i = 0; i < u32text.length(); i++) { -		const char32_t codepoint = u32text[i]; -		if ((codepoint & 0xFF00) == 0xF700) { -			continue; -		} - -		DisplayServerOSX::KeyEvent ke; - -		ke.window_id = window_id; -		ke.osx_state = [event modifierFlags]; -		ke.pressed = true; -		ke.echo = false; -		ke.raw = false; // IME input event. -		ke.keycode = Key::NONE; -		ke.physical_keycode = Key::NONE; -		ke.unicode = codepoint; - -		ds->push_to_key_event_buffer(ke); -	} -	[self cancelComposition]; -} - -// MARK: Drag and drop - -- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { -	return NSDragOperationCopy; -} - -- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { -	return NSDragOperationCopy; -} - -- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return NO; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	if (!wd.drop_files_callback.is_null()) { -		Vector<String> files; -		NSPasteboard *pboard = [sender draggingPasteboard]; - -		if (@available(macOS 10.13, *)) { -			NSArray *items = pboard.pasteboardItems; -			for (NSPasteboardItem *item in items) { -				NSString *url = [item stringForType:NSPasteboardTypeFileURL]; -				NSString *file = [NSURL URLWithString:url].path; -				files.push_back(String::utf8([file UTF8String])); -			} -#if !defined(__aarch64__) // Do not build deprectead 10.13 code on ARM. -		} else { -			NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; -			for (NSString *file in filenames) { -				files.push_back(String::utf8([file UTF8String])); -			} -#endif -		} - -		Variant v = files; -		Variant *vp = &v; -		Variant ret; -		Callable::CallError ce; -		wd.drop_files_callback.call((const Variant **)&vp, 1, ret, ce); -	} - -	return NO; -} - -// MARK: Focus - -- (BOOL)canBecomeKeyView { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return YES; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	return !wd.no_focus && !wd.is_popup; -} - -- (BOOL)acceptsFirstResponder { -	return YES; -} - -// MARK: Mouse - -- (void)cursorUpdate:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds) { -		return; -	} - -	ds->cursor_update_shape(); -} - -- (void)processMouseEvent:(NSEvent *)event index:(MouseButton)index mask:(MouseButton)mask pressed:(bool)pressed { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	MouseButton last_button_state = ds->mouse_get_button_state(); - -	if (pressed) { -		last_button_state |= mask; -	} else { -		last_button_state &= (MouseButton)~mask; -	} -	ds->mouse_set_button_state(last_button_state); - -	Ref<InputEventMouseButton> mb; -	mb.instantiate(); -	mb->set_window_id(window_id); -	ds->update_mouse_pos(wd, [event locationInWindow]); -	ds->get_key_modifier_state([event modifierFlags], mb); -	mb->set_button_index(index); -	mb->set_pressed(pressed); -	mb->set_position(wd.mouse_pos); -	mb->set_global_position(wd.mouse_pos); -	mb->set_button_mask(last_button_state); -	if (index == MouseButton::LEFT && pressed) { -		mb->set_double_click([event clickCount] == 2); -	} - -	Input::get_singleton()->parse_input_event(mb); -} - -- (void)mouseDown:(NSEvent *)event { -	if (([event modifierFlags] & NSEventModifierFlagControl)) { -		mouse_down_control = true; -		[self processMouseEvent:event index:MouseButton::RIGHT mask:MouseButton::MASK_RIGHT pressed:true]; -	} else { -		mouse_down_control = false; -		[self processMouseEvent:event index:MouseButton::LEFT mask:MouseButton::MASK_LEFT pressed:true]; -	} -} - -- (void)mouseDragged:(NSEvent *)event { -	[self mouseMoved:event]; -} - -- (void)mouseUp:(NSEvent *)event { -	if (mouse_down_control) { -		[self processMouseEvent:event index:MouseButton::RIGHT mask:MouseButton::MASK_RIGHT pressed:false]; -	} else { -		[self processMouseEvent:event index:MouseButton::LEFT mask:MouseButton::MASK_LEFT pressed:false]; -	} -} - -- (void)mouseMoved:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	NSPoint delta = NSMakePoint([event deltaX], [event deltaY]); -	NSPoint mpos = [event locationInWindow]; - -	if (ds->update_mouse_wrap(wd, delta, mpos, [event timestamp])) { -		return; -	} - -	Ref<InputEventMouseMotion> mm; -	mm.instantiate(); - -	mm->set_window_id(window_id); -	mm->set_button_mask(ds->mouse_get_button_state()); -	ds->update_mouse_pos(wd, mpos); -	mm->set_position(wd.mouse_pos); -	mm->set_pressure([event pressure]); -	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()); -	const Vector2i relativeMotion = Vector2i(delta.x, delta.y) * ds->screen_get_max_scale(); -	mm->set_relative(relativeMotion); -	ds->get_key_modifier_state([event modifierFlags], mm); - -	Input::get_singleton()->parse_input_event(mm); -} - -- (void)rightMouseDown:(NSEvent *)event { -	[self processMouseEvent:event index:MouseButton::RIGHT mask:MouseButton::MASK_RIGHT pressed:true]; -} - -- (void)rightMouseDragged:(NSEvent *)event { -	[self mouseMoved:event]; -} - -- (void)rightMouseUp:(NSEvent *)event { -	[self processMouseEvent:event index:MouseButton::RIGHT mask:MouseButton::MASK_RIGHT pressed:false]; -} - -- (void)otherMouseDown:(NSEvent *)event { -	if ((int)[event buttonNumber] == 2) { -		[self processMouseEvent:event index:MouseButton::MIDDLE mask:MouseButton::MASK_MIDDLE pressed:true]; -	} else if ((int)[event buttonNumber] == 3) { -		[self processMouseEvent:event index:MouseButton::MB_XBUTTON1 mask:MouseButton::MASK_XBUTTON1 pressed:true]; -	} else if ((int)[event buttonNumber] == 4) { -		[self processMouseEvent:event index:MouseButton::MB_XBUTTON2 mask:MouseButton::MASK_XBUTTON2 pressed:true]; -	} else { -		return; -	} -} - -- (void)otherMouseDragged:(NSEvent *)event { -	[self mouseMoved:event]; -} - -- (void)otherMouseUp:(NSEvent *)event { -	if ((int)[event buttonNumber] == 2) { -		[self processMouseEvent:event index:MouseButton::MIDDLE mask:MouseButton::MASK_MIDDLE pressed:false]; -	} else if ((int)[event buttonNumber] == 3) { -		[self processMouseEvent:event index:MouseButton::MB_XBUTTON1 mask:MouseButton::MASK_XBUTTON1 pressed:false]; -	} else if ((int)[event buttonNumber] == 4) { -		[self processMouseEvent:event index:MouseButton::MB_XBUTTON2 mask:MouseButton::MASK_XBUTTON2 pressed:false]; -	} else { -		return; -	} -} - -- (void)mouseExited:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::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); -	} -} - -- (void)mouseEntered:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::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->cursor_update_shape(); -} - -- (void)magnifyWithEvent:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	Ref<InputEventMagnifyGesture> ev; -	ev.instantiate(); -	ev->set_window_id(window_id); -	ds->get_key_modifier_state([event modifierFlags], ev); -	ds->update_mouse_pos(wd, [event locationInWindow]); -	ev->set_position(wd.mouse_pos); -	ev->set_factor([event magnification] + 1.0); - -	Input::get_singleton()->parse_input_event(ev); -} - -- (void)updateTrackingAreas { -	if (tracking_area != nil) { -		[self removeTrackingArea:tracking_area]; -	} - -	NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingCursorUpdate | NSTrackingInVisibleRect; -	tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; - -	[self addTrackingArea:tracking_area]; -	[super updateTrackingAreas]; -} - -// MARK: Keyboard - -- (void)keyDown:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	ignore_momentum_scroll = true; - -	// Ignore all input if IME input is in progress. -	if (!ime_input_event_in_progress) { -		NSString *characters = [event characters]; -		NSUInteger length = [characters length]; - -		if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]))) { -			// Fallback unicode character handler used if IME is not active. -			Char16String text; -			text.resize([characters length] + 1); -			[characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])]; - -			String u32text; -			u32text.parse_utf16(text.ptr(), text.length()); - -			for (int i = 0; i < u32text.length(); i++) { -				const char32_t codepoint = u32text[i]; - -				DisplayServerOSX::KeyEvent ke; - -				ke.window_id = window_id; -				ke.osx_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.raw = true; -				ke.unicode = codepoint; - -				ds->push_to_key_event_buffer(ke); -			} -		} else { -			DisplayServerOSX::KeyEvent ke; - -			ke.window_id = window_id; -			ke.osx_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.raw = false; -			ke.unicode = 0; - -			ds->push_to_key_event_buffer(ke); -		} -	} - -	// Pass events to IME handler -	if (wd.im_active) { -		[self interpretKeyEvents:[NSArray arrayWithObject:event]]; -	} -} - -- (void)flagsChanged:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} -	ignore_momentum_scroll = true; - -	// Ignore all input if IME input is in progress -	if (!ime_input_event_in_progress) { -		DisplayServerOSX::KeyEvent ke; - -		ke.window_id = window_id; -		ke.echo = false; -		ke.raw = true; - -		int key = [event keyCode]; -		int mod = [event modifierFlags]; - -		if (key == 0x36 || key == 0x37) { -			if (mod & NSEventModifierFlagCommand) { -				mod &= ~NSEventModifierFlagCommand; -				ke.pressed = true; -			} else { -				ke.pressed = false; -			} -		} else if (key == 0x38 || key == 0x3c) { -			if (mod & NSEventModifierFlagShift) { -				mod &= ~NSEventModifierFlagShift; -				ke.pressed = true; -			} else { -				ke.pressed = false; -			} -		} else if (key == 0x3a || key == 0x3d) { -			if (mod & NSEventModifierFlagOption) { -				mod &= ~NSEventModifierFlagOption; -				ke.pressed = true; -			} else { -				ke.pressed = false; -			} -		} else if (key == 0x3b || key == 0x3e) { -			if (mod & NSEventModifierFlagControl) { -				mod &= ~NSEventModifierFlagControl; -				ke.pressed = true; -			} else { -				ke.pressed = false; -			} -		} else { -			return; -		} - -		ke.osx_state = mod; -		ke.keycode = KeyMappingOSX::remap_key(key, mod); -		ke.physical_keycode = KeyMappingOSX::translate_key(key); -		ke.unicode = 0; - -		ds->push_to_key_event_buffer(ke); -	} -} - -- (void)keyUp:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	// Ignore all input if IME input is in progress. -	if (!ime_input_event_in_progress) { -		NSString *characters = [event characters]; -		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]))) { -			Char16String text; -			text.resize([characters length] + 1); -			[characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])]; - -			String u32text; -			u32text.parse_utf16(text.ptr(), text.length()); - -			for (int i = 0; i < u32text.length(); i++) { -				const char32_t codepoint = u32text[i]; -				DisplayServerOSX::KeyEvent ke; - -				ke.window_id = window_id; -				ke.osx_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.raw = true; -				ke.unicode = codepoint; - -				ds->push_to_key_event_buffer(ke); -			} -		} else { -			DisplayServerOSX::KeyEvent ke; - -			ke.window_id = window_id; -			ke.osx_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.raw = true; -			ke.unicode = 0; - -			ds->push_to_key_event_buffer(ke); -		} -	} -} - -// MARK: Scroll and pan - -- (void)processScrollEvent:(NSEvent *)event button:(MouseButton)button factor:(double)factor { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	MouseButton mask = mouse_button_to_mask(button); - -	Ref<InputEventMouseButton> sc; -	sc.instantiate(); - -	sc->set_window_id(window_id); -	ds->get_key_modifier_state([event modifierFlags], sc); -	sc->set_button_index(button); -	sc->set_factor(factor); -	sc->set_pressed(true); -	sc->set_position(wd.mouse_pos); -	sc->set_global_position(wd.mouse_pos); -	MouseButton last_button_state = ds->mouse_get_button_state() | (MouseButton)mask; -	sc->set_button_mask(last_button_state); -	ds->mouse_set_button_state(last_button_state); - -	Input::get_singleton()->parse_input_event(sc); - -	sc.instantiate(); -	sc->set_window_id(window_id); -	sc->set_button_index(button); -	sc->set_factor(factor); -	sc->set_pressed(false); -	sc->set_position(wd.mouse_pos); -	sc->set_global_position(wd.mouse_pos); -	last_button_state &= (MouseButton)~mask; -	sc->set_button_mask(last_button_state); -	ds->mouse_set_button_state(last_button_state); - -	Input::get_singleton()->parse_input_event(sc); -} - -- (void)processPanEvent:(NSEvent *)event dx:(double)dx dy:(double)dy { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	Ref<InputEventPanGesture> pg; -	pg.instantiate(); - -	pg->set_window_id(window_id); -	ds->get_key_modifier_state([event modifierFlags], pg); -	pg->set_position(wd.mouse_pos); -	pg->set_delta(Vector2(-dx, -dy)); - -	Input::get_singleton()->parse_input_event(pg); -} - -- (void)scrollWheel:(NSEvent *)event { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	ds->update_mouse_pos(wd, [event locationInWindow]); - -	double delta_x = [event scrollingDeltaX]; -	double delta_y = [event scrollingDeltaY]; - -	if ([event hasPreciseScrollingDeltas]) { -		delta_x *= 0.03; -		delta_y *= 0.03; -	} - -	if ([event momentumPhase] != NSEventPhaseNone) { -		if (ignore_momentum_scroll) { -			return; -		} -	} else { -		ignore_momentum_scroll = false; -	} - -	if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) { -		[self processPanEvent:event dx:delta_x dy:delta_y]; -	} else { -		if (fabs(delta_x)) { -			[self processScrollEvent:event button:(0 > delta_x ? MouseButton::WHEEL_RIGHT : MouseButton::WHEEL_LEFT) factor:fabs(delta_x * 0.3)]; -		} -		if (fabs(delta_y)) { -			[self processScrollEvent:event button:(0 < delta_y ? MouseButton::WHEEL_UP : MouseButton::WHEEL_DOWN) factor:fabs(delta_y * 0.3)]; -		} -	} -} - -@end diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm deleted file mode 100644 index 722928ad60..0000000000 --- a/platform/osx/godot_main_osx.mm +++ /dev/null @@ -1,92 +0,0 @@ -/*************************************************************************/ -/*  godot_main_osx.mm                                                    */ -/*************************************************************************/ -/*                       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 "main/main.h" - -#include "os_osx.h" - -#include <string.h> -#include <unistd.h> - -#if defined(SANITIZERS_ENABLED) -#include <sys/resource.h> -#endif - -int main(int argc, char **argv) { -#if defined(VULKAN_ENABLED) -	// MoltenVK - enable full component swizzling support. -	setenv("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1); -#endif - -#if defined(SANITIZERS_ENABLED) -	// Note: Set stack size to be at least 30 MB (vs 8 MB default) to avoid overflow, address sanitizer can increase stack usage up to 3 times. -	struct rlimit stack_lim = { 0x1E00000, 0x1E00000 }; -	setrlimit(RLIMIT_STACK, &stack_lim); -#endif - -	int first_arg = 1; -	const char *dbg_arg = "-NSDocumentRevisionsDebugMode"; -	printf("arguments\n"); -	for (int i = 0; i < argc; i++) { -		if (strcmp(dbg_arg, argv[i]) == 0) { -			first_arg = i + 2; -		} -		printf("%i: %s\n", i, argv[i]); -	} - -#ifdef DEBUG_ENABLED -	// Lets report the path we made current after all that. -	char cwd[4096]; -	getcwd(cwd, 4096); -	printf("Current path: %s\n", cwd); -#endif - -	OS_OSX os; -	Error err; - -	// We must override main when testing is enabled. -	TEST_MAIN_OVERRIDE - -	err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]); - -	if (err == ERR_HELP) { // Returned by --help and --version, so success. -		return 0; -	} else if (err != OK) { -		return 255; -	} - -	if (Main::start()) { -		os.run(); // It is actually the OS that decides how to run. -	} - -	Main::cleanup(); - -	return os.get_exit_code(); -} diff --git a/platform/osx/godot_menu_item.h b/platform/osx/godot_menu_item.h deleted file mode 100644 index 2c12897f10..0000000000 --- a/platform/osx/godot_menu_item.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/*  godot_menu_item.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 GODOT_MENU_ITEM_H -#define GODOT_MENU_ITEM_H - -#include "servers/display_server.h" - -#import <AppKit/AppKit.h> -#import <Foundation/Foundation.h> - -enum GlobalMenuCheckType { -	CHECKABLE_TYPE_NONE, -	CHECKABLE_TYPE_CHECK_BOX, -	CHECKABLE_TYPE_RADIO_BUTTON, -}; - -@interface GodotMenuItem : NSObject { -@public -	Callable callback; -	Variant meta; -	int id; -	GlobalMenuCheckType checkable_type; -	int max_states; -	int state; -	Ref<Image> img; -} - -@end - -@implementation GodotMenuItem -@end - -#endif // GODOT_MENU_ITEM_H diff --git a/platform/osx/godot_window.h b/platform/osx/godot_window.h deleted file mode 100644 index 16ff101142..0000000000 --- a/platform/osx/godot_window.h +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************/ -/*  godot_window.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 GODOT_WINDOW_H -#define GODOT_WINDOW_H - -#include "servers/display_server.h" - -#import <AppKit/AppKit.h> -#import <Foundation/Foundation.h> - -@interface GodotWindow : NSWindow { -	DisplayServer::WindowID window_id; -} - -- (void)setWindowID:(DisplayServer::WindowID)wid; - -@end - -#endif //GODOT_WINDOW_H diff --git a/platform/osx/godot_window.mm b/platform/osx/godot_window.mm deleted file mode 100644 index d43853a94b..0000000000 --- a/platform/osx/godot_window.mm +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************/ -/*  godot_window.mm                                                      */ -/*************************************************************************/ -/*                       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 "godot_window.h" - -#include "display_server_osx.h" - -@implementation GodotWindow - -- (id)init { -	self = [super init]; -	window_id = DisplayServer::INVALID_WINDOW_ID; -	return self; -} - -- (void)setWindowID:(DisplayServerOSX::WindowID)wid { -	window_id = wid; -} - -- (BOOL)canBecomeKeyWindow { -	// Required for NSWindowStyleMaskBorderless windows. -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return YES; -	} - -	DisplayServerOSX::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(); -	if (!ds || !ds->has_window(window_id)) { -		return YES; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	return !wd.no_focus && !wd.is_popup; -} - -@end diff --git a/platform/osx/godot_window_delegate.h b/platform/osx/godot_window_delegate.h deleted file mode 100644 index 8a1f681fcd..0000000000 --- a/platform/osx/godot_window_delegate.h +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************/ -/*  godot_window_delegate.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 GODOT_WINDOW_DELEGATE_H -#define GODOT_WINDOW_DELEGATE_H - -#include "servers/display_server.h" - -#import <AppKit/AppKit.h> -#import <Foundation/Foundation.h> - -@interface GodotWindowDelegate : NSObject <NSWindowDelegate> { -	DisplayServer::WindowID window_id; -} - -- (void)setWindowID:(DisplayServer::WindowID)wid; - -@end - -#endif //GODOT_WINDOW_DELEGATE_H diff --git a/platform/osx/godot_window_delegate.mm b/platform/osx/godot_window_delegate.mm deleted file mode 100644 index 521127f01b..0000000000 --- a/platform/osx/godot_window_delegate.mm +++ /dev/null @@ -1,270 +0,0 @@ -/*************************************************************************/ -/*  godot_window_delegate.mm                                             */ -/*************************************************************************/ -/*                       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 "godot_window_delegate.h" - -#include "display_server_osx.h" - -@implementation GodotWindowDelegate - -- (void)setWindowID:(DisplayServer::WindowID)wid { -	window_id = wid; -} - -- (BOOL)windowShouldClose:(id)sender { -	DisplayServerOSX *ds = (DisplayServerOSX *)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); -	return NO; -} - -- (void)windowWillClose:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	ds->popup_close(window_id); - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	while (wd.transient_children.size()) { -		ds->window_set_transient(*wd.transient_children.begin(), DisplayServerOSX::INVALID_WINDOW_ID); -	} - -	if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) { -		ds->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID); -	} - -	ds->window_destroy(window_id); -} - -- (void)windowDidEnterFullScreen:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	wd.fullscreen = true; -	// Reset window size limits. -	[wd.window_object setContentMinSize:NSMakeSize(0, 0)]; -	[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; - -	// Force window resize event. -	[self windowDidResize:notification]; -} - -- (void)windowDidExitFullScreen:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	wd.fullscreen = false; - -	// Set window size limits. -	const float scale = ds->screen_get_max_scale(); -	if (wd.min_size != Size2i()) { -		Size2i size = wd.min_size / scale; -		[wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)]; -	} -	if (wd.max_size != Size2i()) { -		Size2i size = wd.max_size / scale; -		[wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)]; -	} - -	// Restore resizability state. -	if (wd.resize_disabled) { -		[wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable]; -	} - -	// Restore on-top state. -	if (wd.on_top) { -		[wd.window_object setLevel:NSFloatingWindowLevel]; -	} - -	// Force window resize event. -	[self windowDidResize:notification]; -} - -- (void)windowDidChangeBackingProperties:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	CGFloat new_scale_factor = [wd.window_object backingScaleFactor]; -	CGFloat old_scale_factor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; - -	if (new_scale_factor != old_scale_factor) { -		// Set new display scale and window size. -		const float scale = ds->screen_get_max_scale(); -		const NSRect content_rect = [wd.window_view frame]; - -		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); - -		CALayer *layer = [wd.window_view layer]; -		if (layer) { -			layer.contentsScale = scale; -		} - -		//Force window resize event -		[self windowDidResize:notification]; -	} -} - -- (void)windowWillStartLiveResize:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (ds) { -		ds->set_is_resizing(true); -	} -} - -- (void)windowDidEndLiveResize:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (ds) { -		ds->set_is_resizing(false); -	} -} - -- (void)windowDidResize:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::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; -	wd.size.height = content_rect.size.height * scale; - -	CALayer *layer = [wd.window_view layer]; -	if (layer) { -		layer.contentsScale = scale; -	} - -	ds->window_resize(window_id, wd.size.width, wd.size.height); - -	if (!wd.rect_changed_callback.is_null()) { -		Variant size = Rect2i(ds->window_get_position(window_id), ds->window_get_size(window_id)); -		Variant *sizep = &size; -		Variant ret; -		Callable::CallError ce; -		wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); -	} -} - -- (void)windowDidMove:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); -	ds->release_pressed_events(); - -	if (!wd.rect_changed_callback.is_null()) { -		Variant size = Rect2i(ds->window_get_position(window_id), ds->window_get_size(window_id)); -		Variant *sizep = &size; -		Variant ret; -		Callable::CallError ce; -		wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); -	} -} - -- (void)windowDidBecomeKey:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	if (ds->mouse_get_mode() == DisplayServer::MOUSE_MODE_CAPTURED) { -		const NSRect content_rect = [wd.window_view frame]; -		NSRect point_in_window_rect = NSMakeRect(content_rect.size.width / 2, content_rect.size.height / 2, 0, 0); -		NSPoint point_on_screen = [[wd.window_view window] convertRectToScreen:point_in_window_rect].origin; -		CGPoint mouse_warp_pos = { point_on_screen.x, CGDisplayBounds(CGMainDisplayID()).size.height - point_on_screen.y }; -		CGWarpMouseCursorPosition(mouse_warp_pos); -	} else { -		ds->update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); -	} - -	ds->set_last_focused_window(window_id); -	ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); -} - -- (void)windowDidResignKey:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	ds->release_pressed_events(); -	ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT); -} - -- (void)windowDidMiniaturize:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	ds->release_pressed_events(); -	ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT); -} - -- (void)windowDidDeminiaturize:(NSNotification *)notification { -	DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); -	if (!ds || !ds->has_window(window_id)) { -		return; -	} - -	DisplayServerOSX::WindowData &wd = ds->get_window(window_id); - -	ds->set_last_focused_window(window_id); -	ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); -} - -@end diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp deleted file mode 100644 index be9567e17c..0000000000 --- a/platform/osx/joypad_osx.cpp +++ /dev/null @@ -1,616 +0,0 @@ -/*************************************************************************/ -/*  joypad_osx.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 "joypad_osx.h" - -#include <machine/endian.h> - -#define GODOT_JOY_LOOP_RUN_MODE CFSTR("GodotJoypad") - -static JoypadOSX *self = nullptr; - -joypad::joypad() { -	ff_constant_force.lMagnitude = 10000; -	ff_effect.dwDuration = 0; -	ff_effect.dwSamplePeriod = 0; -	ff_effect.dwGain = 10000; -	ff_effect.dwFlags = FFEFF_OBJECTOFFSETS; -	ff_effect.dwTriggerButton = FFEB_NOTRIGGER; -	ff_effect.dwStartDelay = 0; -	ff_effect.dwTriggerRepeatInterval = 0; -	ff_effect.lpEnvelope = nullptr; -	ff_effect.cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); -	ff_effect.lpvTypeSpecificParams = &ff_constant_force; -	ff_effect.dwSize = sizeof(ff_effect); -} - -void joypad::free() { -	if (device_ref) { -		IOHIDDeviceUnscheduleFromRunLoop(device_ref, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); -	} -	if (ff_device) { -		FFDeviceReleaseEffect(ff_device, ff_object); -		FFReleaseDevice(ff_device); -		ff_device = nullptr; -		memfree(ff_axes); -		memfree(ff_directions); -	} -} - -bool joypad::has_element(IOHIDElementCookie p_cookie, Vector<rec_element> *p_list) const { -	for (int i = 0; i < p_list->size(); i++) { -		if (p_cookie == p_list->get(i).cookie) { -			return true; -		} -	} -	return false; -} - -int joypad::get_hid_element_state(rec_element *p_element) const { -	int value = 0; -	if (p_element && p_element->ref) { -		IOHIDValueRef valueRef; -		if (IOHIDDeviceGetValue(device_ref, p_element->ref, &valueRef) == kIOReturnSuccess) { -			value = (SInt32)IOHIDValueGetIntegerValue(valueRef); - -			// Record min and max for auto calibration. -			if (value < p_element->min) { -				p_element->min = value; -			} -			if (value > p_element->max) { -				p_element->max = value; -			} -		} -	} -	return value; -} - -void joypad::add_hid_element(IOHIDElementRef p_element) { -	const CFTypeID elementTypeID = p_element ? CFGetTypeID(p_element) : 0; - -	if (p_element && (elementTypeID == IOHIDElementGetTypeID())) { -		const IOHIDElementCookie cookie = IOHIDElementGetCookie(p_element); -		const uint32_t usagePage = IOHIDElementGetUsagePage(p_element); -		const uint32_t usage = IOHIDElementGetUsage(p_element); -		Vector<rec_element> *list = nullptr; - -		switch (IOHIDElementGetType(p_element)) { -			case kIOHIDElementTypeInput_Misc: -			case kIOHIDElementTypeInput_Button: -			case kIOHIDElementTypeInput_Axis: { -				switch (usagePage) { -					case kHIDPage_GenericDesktop: -						switch (usage) { -							case kHIDUsage_GD_X: -							case kHIDUsage_GD_Y: -							case kHIDUsage_GD_Z: -							case kHIDUsage_GD_Rx: -							case kHIDUsage_GD_Ry: -							case kHIDUsage_GD_Rz: -							case kHIDUsage_GD_Slider: -							case kHIDUsage_GD_Dial: -							case kHIDUsage_GD_Wheel: -								if (!has_element(cookie, &axis_elements)) { -									list = &axis_elements; -								} -								break; - -							case kHIDUsage_GD_Hatswitch: -								if (!has_element(cookie, &hat_elements)) { -									list = &hat_elements; -								} -								break; -							case kHIDUsage_GD_DPadUp: -							case kHIDUsage_GD_DPadDown: -							case kHIDUsage_GD_DPadRight: -							case kHIDUsage_GD_DPadLeft: -							case kHIDUsage_GD_Start: -							case kHIDUsage_GD_Select: -								if (!has_element(cookie, &button_elements)) { -									list = &button_elements; -								} -								break; -						} -						break; - -					case kHIDPage_Simulation: -						switch (usage) { -							case kHIDUsage_Sim_Rudder: -							case kHIDUsage_Sim_Throttle: -							case kHIDUsage_Sim_Accelerator: -							case kHIDUsage_Sim_Brake: -								if (!has_element(cookie, &axis_elements)) { -									list = &axis_elements; -								} -								break; - -							default: -								break; -						} -						break; - -					case kHIDPage_Button: -					case kHIDPage_Consumer: -						if (!has_element(cookie, &button_elements)) { -							list = &button_elements; -						} -						break; - -					default: -						break; -				} -			} break; - -			case kIOHIDElementTypeCollection: { -				CFArrayRef array = IOHIDElementGetChildren(p_element); -				if (array) { -					add_hid_elements(array); -				} -			} break; - -			default: -				break; -		} - -		if (list) { // Add to list. -			rec_element element; - -			element.ref = p_element; -			element.usage = usage; - -			element.min = (SInt32)IOHIDElementGetLogicalMin(p_element); -			element.max = (SInt32)IOHIDElementGetLogicalMax(p_element); -			element.cookie = IOHIDElementGetCookie(p_element); -			list->push_back(element); -			list->sort_custom<rec_element::Comparator>(); -		} -	} -} - -static void hid_element_added(const void *p_value, void *p_parameter) { -	joypad *joy = static_cast<joypad *>(p_parameter); -	joy->add_hid_element((IOHIDElementRef)p_value); -} - -void joypad::add_hid_elements(CFArrayRef p_array) { -	CFRange range = { 0, CFArrayGetCount(p_array) }; -	CFArrayApplyFunction(p_array, range, hid_element_added, this); -} - -static void joypad_removed_callback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject) { -	self->_device_removed(res, ioHIDDeviceObject); -} - -static void joypad_added_callback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject) { -	self->_device_added(res, ioHIDDeviceObject); -} - -static bool is_joypad(IOHIDDeviceRef p_device_ref) { -	int usage_page = 0; -	int usage = 0; -	CFTypeRef refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDPrimaryUsagePageKey)); -	if (refCF) { -		CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &usage_page); -	} -	if (usage_page != kHIDPage_GenericDesktop) { -		return false; -	} - -	refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDPrimaryUsageKey)); -	if (refCF) { -		CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &usage); -	} -	if ((usage != kHIDUsage_GD_Joystick && -				usage != kHIDUsage_GD_GamePad && -				usage != kHIDUsage_GD_MultiAxisController)) { -		return false; -	} -	return true; -} - -void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { -	if (p_res != kIOReturnSuccess || have_device(p_device)) { -		return; -	} - -	joypad new_joypad; -	if (is_joypad(p_device)) { -		configure_joypad(p_device, &new_joypad); -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 -		if (IOHIDDeviceGetService) { -#endif -			const io_service_t ioservice = IOHIDDeviceGetService(p_device); -			if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK) && new_joypad.config_force_feedback(ioservice)) { -				new_joypad.ffservice = ioservice; -			} -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 -		} -#endif -		device_list.push_back(new_joypad); -	} -	IOHIDDeviceScheduleWithRunLoop(p_device, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); -} - -void JoypadOSX::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) { -	int device = get_joy_ref(p_device); -	ERR_FAIL_COND(device == -1); - -	input->joy_connection_changed(device_list[device].id, false, ""); -	device_list.write[device].free(); -	device_list.remove_at(device); -} - -static String _hex_str(uint8_t p_byte) { -	static const char *dict = "0123456789abcdef"; -	char ret[3]; -	ret[2] = 0; - -	ret[0] = dict[p_byte >> 4]; -	ret[1] = dict[p_byte & 0xF]; - -	return ret; -} - -bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { -	p_joy->device_ref = p_device_ref; -	// Get device name. -	String name; -	char c_name[256]; -	CFTypeRef refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDProductKey)); -	if (!refCF) { -		refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDManufacturerKey)); -	} -	if ((!refCF) || (!CFStringGetCString((CFStringRef)refCF, c_name, sizeof(c_name), kCFStringEncodingUTF8))) { -		name = "Unidentified Joypad"; -	} else { -		name = c_name; -	} - -	int id = input->get_unused_joy_id(); -	ERR_FAIL_COND_V(id == -1, false); -	p_joy->id = id; -	int vendor = 0; -	refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDVendorIDKey)); -	if (refCF) { -		CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &vendor); -	} - -	int product_id = 0; -	refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDProductIDKey)); -	if (refCF) { -		CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &product_id); -	} - -	int version = 0; -	refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDVersionNumberKey)); -	if (refCF) { -		CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &version); -	} - -	if (vendor && product_id) { -		char uid[128]; -		sprintf(uid, "%08x%08x%08x%08x", OSSwapHostToBigInt32(3), OSSwapHostToBigInt32(vendor), OSSwapHostToBigInt32(product_id), OSSwapHostToBigInt32(version)); -		input->joy_connection_changed(id, true, name, uid); -	} else { -		// Bluetooth device. -		String guid = "05000000"; -		for (int i = 0; i < 12; i++) { -			if (i < name.size()) { -				guid += _hex_str(name[i]); -			} else { -				guid += "00"; -			} -		} -		input->joy_connection_changed(id, true, name, guid); -	} - -	CFArrayRef array = IOHIDDeviceCopyMatchingElements(p_device_ref, nullptr, kIOHIDOptionsTypeNone); -	if (array) { -		p_joy->add_hid_elements(array); -		CFRelease(array); -	} -	// Xbox controller hat values start at 1 rather than 0. -	p_joy->offset_hat = vendor == 0x45e && -			(product_id == 0x0b05 || -					product_id == 0x02e0 || -					product_id == 0x02fd || -					product_id == 0x0b13); - -	return true; -} - -#define FF_ERR()                        \ -	{                                   \ -		if (ret != FF_OK) {             \ -			FFReleaseDevice(ff_device); \ -			ff_device = nullptr;        \ -			return false;               \ -		}                               \ -	} -bool joypad::config_force_feedback(io_service_t p_service) { -	HRESULT ret = FFCreateDevice(p_service, &ff_device); -	ERR_FAIL_COND_V(ret != FF_OK, false); - -	ret = FFDeviceSendForceFeedbackCommand(ff_device, FFSFFC_RESET); -	FF_ERR(); - -	ret = FFDeviceSendForceFeedbackCommand(ff_device, FFSFFC_SETACTUATORSON); -	FF_ERR(); - -	if (check_ff_features()) { -		ret = FFDeviceCreateEffect(ff_device, kFFEffectType_ConstantForce_ID, &ff_effect, &ff_object); -		FF_ERR(); -		return true; -	} -	FFReleaseDevice(ff_device); -	ff_device = nullptr; -	return false; -} -#undef FF_ERR - -#define TEST_FF(ff) (features.supportedEffects & (ff)) -bool joypad::check_ff_features() { -	FFCAPABILITIES features; -	HRESULT ret = FFDeviceGetForceFeedbackCapabilities(ff_device, &features); -	if (ret == FF_OK && (features.supportedEffects & FFCAP_ET_CONSTANTFORCE)) { -		uint32_t val; -		ret = FFDeviceGetForceFeedbackProperty(ff_device, FFPROP_FFGAIN, &val, sizeof(val)); -		if (ret != FF_OK) { -			return false; -		} -		int num_axes = features.numFfAxes; -		ff_axes = (DWORD *)memalloc(sizeof(DWORD) * num_axes); -		ff_directions = (LONG *)memalloc(sizeof(LONG) * num_axes); - -		for (int i = 0; i < num_axes; i++) { -			ff_axes[i] = features.ffAxes[i]; -			ff_directions[i] = 0; -		} - -		ff_effect.cAxes = num_axes; -		ff_effect.rgdwAxes = ff_axes; -		ff_effect.rglDirection = ff_directions; -		return true; -	} -	return false; -} - -static HatMask process_hat_value(int p_min, int p_max, int p_value, bool p_offset_hat) { -	int range = (p_max - p_min + 1); -	int value = p_value - p_min; -	HatMask hat_value = HatMask::CENTER; -	if (range == 4) { -		value *= 2; -	} -	if (p_offset_hat) { -		value -= 1; -	} - -	switch (value) { -		case 0: -			hat_value = HatMask::UP; -			break; -		case 1: -			hat_value = (HatMask::UP | HatMask::RIGHT); -			break; -		case 2: -			hat_value = HatMask::RIGHT; -			break; -		case 3: -			hat_value = (HatMask::DOWN | HatMask::RIGHT); -			break; -		case 4: -			hat_value = HatMask::DOWN; -			break; -		case 5: -			hat_value = (HatMask::DOWN | HatMask::LEFT); -			break; -		case 6: -			hat_value = HatMask::LEFT; -			break; -		case 7: -			hat_value = (HatMask::UP | HatMask::LEFT); -			break; -		default: -			hat_value = HatMask::CENTER; -			break; -	} -	return hat_value; -} - -void JoypadOSX::poll_joypads() const { -	while (CFRunLoopRunInMode(GODOT_JOY_LOOP_RUN_MODE, 0, TRUE) == kCFRunLoopRunHandledSource) { -		// No-op. Pending callbacks will fire. -	} -} - -static float axis_correct(int p_value, int p_min, int p_max) { -	// Convert to a value between -1.0f and 1.0f. -	return 2.0f * (p_value - p_min) / (p_max - p_min) - 1.0f; -} - -void JoypadOSX::process_joypads() { -	poll_joypads(); - -	for (int i = 0; i < device_list.size(); i++) { -		joypad &joy = device_list.write[i]; - -		for (int j = 0; j < joy.axis_elements.size(); j++) { -			rec_element &elem = joy.axis_elements.write[j]; -			int value = joy.get_hid_element_state(&elem); -			input->joy_axis(joy.id, (JoyAxis)j, axis_correct(value, elem.min, elem.max)); -		} -		for (int j = 0; j < joy.button_elements.size(); j++) { -			int value = joy.get_hid_element_state(&joy.button_elements.write[j]); -			input->joy_button(joy.id, (JoyButton)j, (value >= 1)); -		} -		for (int j = 0; j < joy.hat_elements.size(); j++) { -			rec_element &elem = joy.hat_elements.write[j]; -			int value = joy.get_hid_element_state(&elem); -			HatMask hat_value = process_hat_value(elem.min, elem.max, value, joy.offset_hat); -			input->joy_hat(joy.id, hat_value); -		} - -		if (joy.ffservice) { -			uint64_t timestamp = input->get_joy_vibration_timestamp(joy.id); -			if (timestamp > joy.ff_timestamp) { -				Vector2 strength = input->get_joy_vibration_strength(joy.id); -				float duration = input->get_joy_vibration_duration(joy.id); -				if (strength.x == 0 && strength.y == 0) { -					joypad_vibration_stop(joy.id, timestamp); -				} else { -					float gain = MAX(strength.x, strength.y); -					joypad_vibration_start(joy.id, gain, duration, timestamp); -				} -			} -		} -	} -} - -void JoypadOSX::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; -	joy->ff_effect.dwGain = p_magnitude * FF_FFNOMINALMAX; -	FFEffectSetParameters(joy->ff_object, &joy->ff_effect, FFEP_DURATION | FFEP_GAIN); -	FFEffectStart(joy->ff_object, 1, 0); -} - -void JoypadOSX::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 { -	for (int i = 0; i < device_list.size(); i++) { -		if (device_list[i].id == p_id) { -			return i; -		} -	} -	return -1; -} - -int JoypadOSX::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; -		} -	} -	return -1; -} - -bool JoypadOSX::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; -		} -	} -	return false; -} - -static CFDictionaryRef create_match_dictionary(const UInt32 page, const UInt32 usage, int *okay) { -	CFDictionaryRef retval = nullptr; -	CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); -	CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); - -	if (pageNumRef && usageNumRef) { -		const void *keys[2] = { (void *)CFSTR(kIOHIDDeviceUsagePageKey), (void *)CFSTR(kIOHIDDeviceUsageKey) }; -		const void *vals[2] = { (void *)pageNumRef, (void *)usageNumRef }; -		retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); -	} - -	if (pageNumRef) { -		CFRelease(pageNumRef); -	} -	if (usageNumRef) { -		CFRelease(usageNumRef); -	} - -	if (!retval) { -		*okay = 0; -	} - -	return retval; -} - -void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const { -	CFRunLoopRef runloop = CFRunLoopGetCurrent(); -	IOReturn ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); -	ERR_FAIL_COND(ret != kIOReturnSuccess); - -	IOHIDManagerSetDeviceMatchingMultiple(hid_manager, p_matching_array); -	IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, joypad_added_callback, nullptr); -	IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, joypad_removed_callback, nullptr); -	IOHIDManagerScheduleWithRunLoop(hid_manager, runloop, GODOT_JOY_LOOP_RUN_MODE); - -	while (CFRunLoopRunInMode(GODOT_JOY_LOOP_RUN_MODE, 0, TRUE) == kCFRunLoopRunHandledSource) { -		// No-op. Callback fires once per existing device. -	} -} - -JoypadOSX::JoypadOSX(Input *in) { -	self = this; -	input = in; - -	int okay = 1; -	const void *vals[] = { -		(void *)create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, &okay), -		(void *)create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, &okay), -		(void *)create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController, &okay), -	}; -	const size_t n_elements = sizeof(vals) / sizeof(vals[0]); -	CFArrayRef array = okay ? CFArrayCreate(kCFAllocatorDefault, vals, n_elements, &kCFTypeArrayCallBacks) : nullptr; - -	for (size_t i = 0; i < n_elements; i++) { -		if (vals[i]) { -			CFRelease((CFTypeRef)vals[i]); -		} -	} - -	if (array) { -		hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); -		if (hid_manager) { -			config_hid_manager(array); -		} -		CFRelease(array); -	} -} - -JoypadOSX::~JoypadOSX() { -	for (int i = 0; i < device_list.size(); i++) { -		device_list.write[i].free(); -	} - -	IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); -	IOHIDManagerClose(hid_manager, kIOHIDOptionsTypeNone); -	CFRelease(hid_manager); -	hid_manager = nullptr; -} diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h deleted file mode 100644 index 3f89048ce6..0000000000 --- a/platform/osx/joypad_osx.h +++ /dev/null @@ -1,124 +0,0 @@ -/*************************************************************************/ -/*  joypad_osx.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 JOYPADOSX_H -#define JOYPADOSX_H - -#ifdef MACOS_10_0_4 -#import <IOKit/hidsystem/IOHIDUsageTables.h> -#else -#import <Kernel/IOKit/hidsystem/IOHIDUsageTables.h> -#endif -#import <ForceFeedback/ForceFeedback.h> -#import <ForceFeedback/ForceFeedbackConstants.h> -#import <IOKit/hid/IOHIDLib.h> - -#include "core/input/input.h" - -struct rec_element { -	IOHIDElementRef ref; -	IOHIDElementCookie cookie; - -	uint32_t usage = 0; - -	int min = 0; -	int max = 0; - -	struct Comparator { -		bool operator()(const rec_element p_a, const rec_element p_b) const { return p_a.usage < p_b.usage; } -	}; -}; - -struct joypad { -	IOHIDDeviceRef device_ref = nullptr; - -	Vector<rec_element> axis_elements; -	Vector<rec_element> button_elements; -	Vector<rec_element> hat_elements; - -	int id = 0; -	bool offset_hat = false; - -	io_service_t ffservice = 0; // Interface for force feedback, 0 = no ff. -	FFCONSTANTFORCE ff_constant_force; -	FFDeviceObjectReference ff_device = nullptr; -	FFEffectObjectReference ff_object = nullptr; -	uint64_t ff_timestamp = 0; -	LONG *ff_directions = nullptr; -	FFEFFECT ff_effect; -	DWORD *ff_axes = nullptr; - -	void add_hid_elements(CFArrayRef p_array); -	void add_hid_element(IOHIDElementRef p_element); - -	bool has_element(IOHIDElementCookie p_cookie, Vector<rec_element> *p_list) const; -	bool config_force_feedback(io_service_t p_service); -	bool check_ff_features(); - -	int get_hid_element_state(rec_element *p_element) const; - -	void free(); -	joypad(); -}; - -class JoypadOSX { -	enum { -		JOYPADS_MAX = 16, -	}; - -private: -	Input *input = nullptr; -	IOHIDManagerRef hid_manager; - -	Vector<joypad> device_list; - -	bool have_device(IOHIDDeviceRef p_device) const; -	bool configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy); - -	int get_joy_index(int p_id) const; -	int get_joy_ref(IOHIDDeviceRef p_device) const; - -	void poll_joypads() const; -	void config_hid_manager(CFArrayRef p_matching_array) const; - -	void joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp); -	void joypad_vibration_stop(int p_id, uint64_t p_timestamp); - -public: -	void process_joypads(); - -	void _device_added(IOReturn p_res, IOHIDDeviceRef p_device); -	void _device_removed(IOReturn p_res, IOHIDDeviceRef p_device); - -	JoypadOSX(Input *in); -	~JoypadOSX(); -}; - -#endif // JOYPADOSX_H diff --git a/platform/osx/key_mapping_osx.h b/platform/osx/key_mapping_osx.h deleted file mode 100644 index 252cc907bb..0000000000 --- a/platform/osx/key_mapping_osx.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/*  key_mapping_osx.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 KEY_MAPPING_OSX_H -#define KEY_MAPPING_OSX_H - -#include "core/os/keyboard.h" - -class KeyMappingOSX { -	KeyMappingOSX() {} - -	static bool is_numpad_key(unsigned int key); - -public: -	// Mappings input. -	static Key translate_key(unsigned int key); -	static unsigned int unmap_key(Key key); -	static Key remap_key(unsigned int key, unsigned int state); - -	// Mapping for menu shortcuts. -	static String keycode_get_native_string(Key p_keycode); -	static unsigned int keycode_get_native_mask(Key p_keycode); -}; - -#endif // KEY_MAPPING_OSX_H diff --git a/platform/osx/key_mapping_osx.mm b/platform/osx/key_mapping_osx.mm deleted file mode 100644 index 0bf6bc7d1c..0000000000 --- a/platform/osx/key_mapping_osx.mm +++ /dev/null @@ -1,496 +0,0 @@ -/*************************************************************************/ -/*  key_mapping_osx.mm                                                   */ -/*************************************************************************/ -/*                       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 "key_mapping_osx.h" - -#import <Carbon/Carbon.h> -#import <Cocoa/Cocoa.h> - -bool KeyMappingOSX::is_numpad_key(unsigned int key) { -	static const unsigned int table[] = { -		0x41, /* kVK_ANSI_KeypadDecimal */ -		0x43, /* kVK_ANSI_KeypadMultiply */ -		0x45, /* kVK_ANSI_KeypadPlus */ -		0x47, /* kVK_ANSI_KeypadClear */ -		0x4b, /* kVK_ANSI_KeypadDivide */ -		0x4c, /* kVK_ANSI_KeypadEnter */ -		0x4e, /* kVK_ANSI_KeypadMinus */ -		0x51, /* kVK_ANSI_KeypadEquals */ -		0x52, /* kVK_ANSI_Keypad0 */ -		0x53, /* kVK_ANSI_Keypad1 */ -		0x54, /* kVK_ANSI_Keypad2 */ -		0x55, /* kVK_ANSI_Keypad3 */ -		0x56, /* kVK_ANSI_Keypad4 */ -		0x57, /* kVK_ANSI_Keypad5 */ -		0x58, /* kVK_ANSI_Keypad6 */ -		0x59, /* kVK_ANSI_Keypad7 */ -		0x5b, /* kVK_ANSI_Keypad8 */ -		0x5c, /* kVK_ANSI_Keypad9 */ -		0x5f, /* kVK_JIS_KeypadComma */ -		0x00 -	}; -	for (int i = 0; table[i] != 0; i++) { -		if (key == table[i]) { -			return true; -		} -	} -	return false; -} - -// Keyboard symbol translation table. -static const Key _osx_to_godot_table[128] = { -	/* 00 */ Key::A, -	/* 01 */ Key::S, -	/* 02 */ Key::D, -	/* 03 */ Key::F, -	/* 04 */ Key::H, -	/* 05 */ Key::G, -	/* 06 */ Key::Z, -	/* 07 */ Key::X, -	/* 08 */ Key::C, -	/* 09 */ Key::V, -	/* 0a */ Key::SECTION, /* ISO Section */ -	/* 0b */ Key::B, -	/* 0c */ Key::Q, -	/* 0d */ Key::W, -	/* 0e */ Key::E, -	/* 0f */ Key::R, -	/* 10 */ Key::Y, -	/* 11 */ Key::T, -	/* 12 */ Key::KEY_1, -	/* 13 */ Key::KEY_2, -	/* 14 */ Key::KEY_3, -	/* 15 */ Key::KEY_4, -	/* 16 */ Key::KEY_6, -	/* 17 */ Key::KEY_5, -	/* 18 */ Key::EQUAL, -	/* 19 */ Key::KEY_9, -	/* 1a */ Key::KEY_7, -	/* 1b */ Key::MINUS, -	/* 1c */ Key::KEY_8, -	/* 1d */ Key::KEY_0, -	/* 1e */ Key::BRACERIGHT, -	/* 1f */ Key::O, -	/* 20 */ Key::U, -	/* 21 */ Key::BRACELEFT, -	/* 22 */ Key::I, -	/* 23 */ Key::P, -	/* 24 */ Key::ENTER, -	/* 25 */ Key::L, -	/* 26 */ Key::J, -	/* 27 */ Key::APOSTROPHE, -	/* 28 */ Key::K, -	/* 29 */ Key::SEMICOLON, -	/* 2a */ Key::BACKSLASH, -	/* 2b */ Key::COMMA, -	/* 2c */ Key::SLASH, -	/* 2d */ Key::N, -	/* 2e */ Key::M, -	/* 2f */ Key::PERIOD, -	/* 30 */ Key::TAB, -	/* 31 */ Key::SPACE, -	/* 32 */ Key::QUOTELEFT, -	/* 33 */ Key::BACKSPACE, -	/* 34 */ Key::UNKNOWN, -	/* 35 */ Key::ESCAPE, -	/* 36 */ Key::META, -	/* 37 */ Key::META, -	/* 38 */ Key::SHIFT, -	/* 39 */ Key::CAPSLOCK, -	/* 3a */ Key::ALT, -	/* 3b */ Key::CTRL, -	/* 3c */ Key::SHIFT, -	/* 3d */ Key::ALT, -	/* 3e */ Key::CTRL, -	/* 3f */ Key::UNKNOWN, /* Function */ -	/* 40 */ Key::F17, -	/* 41 */ Key::KP_PERIOD, -	/* 42 */ Key::UNKNOWN, -	/* 43 */ Key::KP_MULTIPLY, -	/* 44 */ Key::UNKNOWN, -	/* 45 */ Key::KP_ADD, -	/* 46 */ Key::UNKNOWN, -	/* 47 */ Key::NUMLOCK, /* Really KeypadClear... */ -	/* 48 */ Key::VOLUMEUP, /* VolumeUp */ -	/* 49 */ Key::VOLUMEDOWN, /* VolumeDown */ -	/* 4a */ Key::VOLUMEMUTE, /* Mute */ -	/* 4b */ Key::KP_DIVIDE, -	/* 4c */ Key::KP_ENTER, -	/* 4d */ Key::UNKNOWN, -	/* 4e */ Key::KP_SUBTRACT, -	/* 4f */ Key::F18, -	/* 50 */ Key::F19, -	/* 51 */ Key::EQUAL, /* KeypadEqual */ -	/* 52 */ Key::KP_0, -	/* 53 */ Key::KP_1, -	/* 54 */ Key::KP_2, -	/* 55 */ Key::KP_3, -	/* 56 */ Key::KP_4, -	/* 57 */ Key::KP_5, -	/* 58 */ Key::KP_6, -	/* 59 */ Key::KP_7, -	/* 5a */ Key::F20, -	/* 5b */ Key::KP_8, -	/* 5c */ Key::KP_9, -	/* 5d */ Key::YEN, /* JIS Yen */ -	/* 5e */ Key::UNDERSCORE, /* JIS Underscore */ -	/* 5f */ Key::COMMA, /* JIS KeypadComma */ -	/* 60 */ Key::F5, -	/* 61 */ Key::F6, -	/* 62 */ Key::F7, -	/* 63 */ Key::F3, -	/* 64 */ Key::F8, -	/* 65 */ Key::F9, -	/* 66 */ Key::UNKNOWN, /* JIS Eisu */ -	/* 67 */ Key::F11, -	/* 68 */ Key::UNKNOWN, /* JIS Kana */ -	/* 69 */ Key::F13, -	/* 6a */ Key::F16, -	/* 6b */ Key::F14, -	/* 6c */ Key::UNKNOWN, -	/* 6d */ Key::F10, -	/* 6e */ Key::MENU, -	/* 6f */ Key::F12, -	/* 70 */ Key::UNKNOWN, -	/* 71 */ Key::F15, -	/* 72 */ Key::INSERT, /* Really Help... */ -	/* 73 */ Key::HOME, -	/* 74 */ Key::PAGEUP, -	/* 75 */ Key::KEY_DELETE, -	/* 76 */ Key::F4, -	/* 77 */ Key::END, -	/* 78 */ Key::F2, -	/* 79 */ Key::PAGEDOWN, -	/* 7a */ Key::F1, -	/* 7b */ Key::LEFT, -	/* 7c */ Key::RIGHT, -	/* 7d */ Key::DOWN, -	/* 7e */ Key::UP, -	/* 7f */ Key::UNKNOWN, -}; - -// Translates a OS X keycode to a Godot keycode. -Key KeyMappingOSX::translate_key(unsigned int key) { -	if (key >= 128) { -		return Key::UNKNOWN; -	} - -	return _osx_to_godot_table[key]; -} - -// Translates a Godot keycode back to a OSX keycode. -unsigned int KeyMappingOSX::unmap_key(Key key) { -	for (int i = 0; i <= 126; i++) { -		if (_osx_to_godot_table[i] == key) { -			return i; -		} -	} -	return 127; -} - -struct _KeyCodeMap { -	UniChar kchar; -	Key kcode; -}; - -static const _KeyCodeMap _keycodes[55] = { -	{ '`', Key::QUOTELEFT }, -	{ '~', Key::ASCIITILDE }, -	{ '0', Key::KEY_0 }, -	{ '1', Key::KEY_1 }, -	{ '2', Key::KEY_2 }, -	{ '3', Key::KEY_3 }, -	{ '4', Key::KEY_4 }, -	{ '5', Key::KEY_5 }, -	{ '6', Key::KEY_6 }, -	{ '7', Key::KEY_7 }, -	{ '8', Key::KEY_8 }, -	{ '9', Key::KEY_9 }, -	{ '-', Key::MINUS }, -	{ '_', Key::UNDERSCORE }, -	{ '=', Key::EQUAL }, -	{ '+', Key::PLUS }, -	{ 'q', Key::Q }, -	{ 'w', Key::W }, -	{ 'e', Key::E }, -	{ 'r', Key::R }, -	{ 't', Key::T }, -	{ 'y', Key::Y }, -	{ 'u', Key::U }, -	{ 'i', Key::I }, -	{ 'o', Key::O }, -	{ 'p', Key::P }, -	{ '[', Key::BRACELEFT }, -	{ ']', Key::BRACERIGHT }, -	{ '{', Key::BRACELEFT }, -	{ '}', Key::BRACERIGHT }, -	{ 'a', Key::A }, -	{ 's', Key::S }, -	{ 'd', Key::D }, -	{ 'f', Key::F }, -	{ 'g', Key::G }, -	{ 'h', Key::H }, -	{ 'j', Key::J }, -	{ 'k', Key::K }, -	{ 'l', Key::L }, -	{ ';', Key::SEMICOLON }, -	{ ':', Key::COLON }, -	{ '\'', Key::APOSTROPHE }, -	{ '\"', Key::QUOTEDBL }, -	{ '\\', Key::BACKSLASH }, -	{ '#', Key::NUMBERSIGN }, -	{ 'z', Key::Z }, -	{ 'x', Key::X }, -	{ 'c', Key::C }, -	{ 'v', Key::V }, -	{ 'b', Key::B }, -	{ 'n', Key::N }, -	{ 'm', Key::M }, -	{ ',', Key::COMMA }, -	{ '.', Key::PERIOD }, -	{ '/', Key::SLASH } -}; - -// Remap key according to current keyboard layout. -Key KeyMappingOSX::remap_key(unsigned int key, unsigned int state) { -	if (is_numpad_key(key)) { -		return translate_key(key); -	} - -	TISInputSourceRef current_keyboard = TISCopyCurrentKeyboardInputSource(); -	if (!current_keyboard) { -		return translate_key(key); -	} - -	CFDataRef layout_data = (CFDataRef)TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData); -	if (!layout_data) { -		return translate_key(key); -	} - -	const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout *)CFDataGetBytePtr(layout_data); - -	UInt32 keys_down = 0; -	UniChar chars[4]; -	UniCharCount real_length; - -	OSStatus err = UCKeyTranslate(keyboard_layout, -			key, -			kUCKeyActionDisplay, -			(state >> 8) & 0xFF, -			LMGetKbdType(), -			kUCKeyTranslateNoDeadKeysBit, -			&keys_down, -			sizeof(chars) / sizeof(chars[0]), -			&real_length, -			chars); - -	if (err != noErr) { -		return translate_key(key); -	} - -	for (unsigned int i = 0; i < 55; i++) { -		if (_keycodes[i].kchar == chars[0]) { -			return _keycodes[i].kcode; -		} -	} -	return translate_key(key); -} - -struct _KeyCodeText { -	Key code; -	char32_t text; -}; - -static const _KeyCodeText _native_keycodes[] = { -	/* clang-format off */ -		{Key::ESCAPE                        ,0x001B}, -		{Key::TAB                           ,0x0009}, -		{Key::BACKTAB                       ,0x007F}, -		{Key::BACKSPACE                     ,0x0008}, -		{Key::ENTER                         ,0x000D}, -		{Key::INSERT                        ,NSInsertFunctionKey}, -		{Key::KEY_DELETE                    ,0x007F}, -		{Key::PAUSE                         ,NSPauseFunctionKey}, -		{Key::PRINT                         ,NSPrintScreenFunctionKey}, -		{Key::SYSREQ                        ,NSSysReqFunctionKey}, -		{Key::CLEAR                         ,NSClearLineFunctionKey}, -		{Key::HOME                          ,0x2196}, -		{Key::END                           ,0x2198}, -		{Key::LEFT                          ,0x001C}, -		{Key::UP                            ,0x001E}, -		{Key::RIGHT                         ,0x001D}, -		{Key::DOWN                          ,0x001F}, -		{Key::PAGEUP                        ,0x21DE}, -		{Key::PAGEDOWN                      ,0x21DF}, -		{Key::NUMLOCK                       ,NSClearLineFunctionKey}, -		{Key::SCROLLLOCK                    ,NSScrollLockFunctionKey}, -		{Key::F1                            ,NSF1FunctionKey}, -		{Key::F2                            ,NSF2FunctionKey}, -		{Key::F3                            ,NSF3FunctionKey}, -		{Key::F4                            ,NSF4FunctionKey}, -		{Key::F5                            ,NSF5FunctionKey}, -		{Key::F6                            ,NSF6FunctionKey}, -		{Key::F7                            ,NSF7FunctionKey}, -		{Key::F8                            ,NSF8FunctionKey}, -		{Key::F9                            ,NSF9FunctionKey}, -		{Key::F10                           ,NSF10FunctionKey}, -		{Key::F11                           ,NSF11FunctionKey}, -		{Key::F12                           ,NSF12FunctionKey}, -		{Key::F13                           ,NSF13FunctionKey}, -		{Key::F14                           ,NSF14FunctionKey}, -		{Key::F15                           ,NSF15FunctionKey}, -		{Key::F16                           ,NSF16FunctionKey}, -		{Key::F17                           ,NSF17FunctionKey}, -		{Key::F18                           ,NSF18FunctionKey}, -		{Key::F19                           ,NSF19FunctionKey}, -		{Key::F20                           ,NSF20FunctionKey}, -		{Key::F21                           ,NSF21FunctionKey}, -		{Key::F22                           ,NSF22FunctionKey}, -		{Key::F23                           ,NSF23FunctionKey}, -		{Key::F24                           ,NSF24FunctionKey}, -		{Key::F25                           ,NSF25FunctionKey}, -		{Key::F26                           ,NSF26FunctionKey}, -		{Key::F27                           ,NSF27FunctionKey}, -		{Key::F28                           ,NSF28FunctionKey}, -		{Key::F29                           ,NSF29FunctionKey}, -		{Key::F30                           ,NSF30FunctionKey}, -		{Key::F31                           ,NSF31FunctionKey}, -		{Key::F32                           ,NSF32FunctionKey}, -		{Key::F33                           ,NSF33FunctionKey}, -		{Key::F34                           ,NSF34FunctionKey}, -		{Key::F35                           ,NSF35FunctionKey}, -		{Key::MENU                          ,NSMenuFunctionKey}, -		{Key::HELP                          ,NSHelpFunctionKey}, -		{Key::STOP                          ,NSStopFunctionKey}, -		{Key::LAUNCH0                       ,NSUserFunctionKey}, -		{Key::SPACE                         ,0x0020}, -		{Key::EXCLAM                        ,'!'}, -		{Key::QUOTEDBL                      ,'\"'}, -		{Key::NUMBERSIGN                    ,'#'}, -		{Key::DOLLAR                        ,'$'}, -		{Key::PERCENT                       ,'\%'}, -		{Key::AMPERSAND                     ,'&'}, -		{Key::APOSTROPHE                    ,'\''}, -		{Key::PARENLEFT                     ,'('}, -		{Key::PARENRIGHT                    ,')'}, -		{Key::ASTERISK                      ,'*'}, -		{Key::PLUS                          ,'+'}, -		{Key::COMMA                         ,','}, -		{Key::MINUS                         ,'-'}, -		{Key::PERIOD                        ,'.'}, -		{Key::SLASH                         ,'/'}, -		{Key::KEY_0                         ,'0'}, -		{Key::KEY_1                         ,'1'}, -		{Key::KEY_2                         ,'2'}, -		{Key::KEY_3                         ,'3'}, -		{Key::KEY_4                         ,'4'}, -		{Key::KEY_5                         ,'5'}, -		{Key::KEY_6                         ,'6'}, -		{Key::KEY_7                         ,'7'}, -		{Key::KEY_8                         ,'8'}, -		{Key::KEY_9                         ,'9'}, -		{Key::COLON                         ,':'}, -		{Key::SEMICOLON                     ,';'}, -		{Key::LESS                          ,'<'}, -		{Key::EQUAL                         ,'='}, -		{Key::GREATER                       ,'>'}, -		{Key::QUESTION                      ,'?'}, -		{Key::AT                            ,'@'}, -		{Key::A                             ,'a'}, -		{Key::B                             ,'b'}, -		{Key::C                             ,'c'}, -		{Key::D                             ,'d'}, -		{Key::E                             ,'e'}, -		{Key::F                             ,'f'}, -		{Key::G                             ,'g'}, -		{Key::H                             ,'h'}, -		{Key::I                             ,'i'}, -		{Key::J                             ,'j'}, -		{Key::K                             ,'k'}, -		{Key::L                             ,'l'}, -		{Key::M                             ,'m'}, -		{Key::N                             ,'n'}, -		{Key::O                             ,'o'}, -		{Key::P                             ,'p'}, -		{Key::Q                             ,'q'}, -		{Key::R                             ,'r'}, -		{Key::S                             ,'s'}, -		{Key::T                             ,'t'}, -		{Key::U                             ,'u'}, -		{Key::V                             ,'v'}, -		{Key::W                             ,'w'}, -		{Key::X                             ,'x'}, -		{Key::Y                             ,'y'}, -		{Key::Z                             ,'z'}, -		{Key::BRACKETLEFT                   ,'['}, -		{Key::BACKSLASH                     ,'\\'}, -		{Key::BRACKETRIGHT                  ,']'}, -		{Key::ASCIICIRCUM                   ,'^'}, -		{Key::UNDERSCORE                    ,'_'}, -		{Key::QUOTELEFT                     ,'`'}, -		{Key::BRACELEFT                     ,'{'}, -		{Key::BAR                           ,'|'}, -		{Key::BRACERIGHT                    ,'}'}, -		{Key::ASCIITILDE                    ,'~'}, -		{Key::NONE                          ,0x0000} -	/* clang-format on */ -}; - -String KeyMappingOSX::keycode_get_native_string(Key p_keycode) { -	const _KeyCodeText *kct = &_native_keycodes[0]; - -	while (kct->text) { -		if (kct->code == p_keycode) { -			return String::chr(kct->text); -		} -		kct++; -	} -	return String(); -} - -unsigned int KeyMappingOSX::keycode_get_native_mask(Key p_keycode) { -	unsigned int mask = 0; -	if ((p_keycode & KeyModifierMask::CTRL) != Key::NONE) { -		mask |= NSEventModifierFlagControl; -	} -	if ((p_keycode & KeyModifierMask::ALT) != Key::NONE) { -		mask |= NSEventModifierFlagOption; -	} -	if ((p_keycode & KeyModifierMask::SHIFT) != Key::NONE) { -		mask |= NSEventModifierFlagShift; -	} -	if ((p_keycode & KeyModifierMask::META) != Key::NONE) { -		mask |= NSEventModifierFlagCommand; -	} -	if ((p_keycode & KeyModifierMask::KPAD) != Key::NONE) { -		mask |= NSEventModifierFlagNumericPad; -	} -	return mask; -} diff --git a/platform/osx/logo.png b/platform/osx/logo.png Binary files differdeleted file mode 100644 index b5a660b165..0000000000 --- a/platform/osx/logo.png +++ /dev/null diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h deleted file mode 100644 index b105be4a06..0000000000 --- a/platform/osx/os_osx.h +++ /dev/null @@ -1,120 +0,0 @@ -/*************************************************************************/ -/*  os_osx.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 OS_OSX_H -#define OS_OSX_H - -#include "core/input/input.h" -#include "crash_handler_osx.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 "servers/audio_server.h" - -class OS_OSX : public OS_Unix { -	bool force_quit = false; - -	JoypadOSX *joypad_osx = nullptr; - -#ifdef COREAUDIO_ENABLED -	AudioDriverCoreAudio audio_driver; -#endif -#ifdef COREMIDI_ENABLED -	MIDIDriverCoreMidi midi_driver; -#endif - -	CrashHandler crash_handler; - -	CFRunLoopObserverRef pre_wait_observer; - -	MainLoop *main_loop = nullptr; - -	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); - -protected: -	virtual void initialize_core() override; -	virtual void initialize() override; -	virtual void finalize() override; - -	virtual void initialize_joypads() override; - -	virtual void set_main_loop(MainLoop *p_main_loop) override; -	virtual void delete_main_loop() override; - -public: -	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; - -	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; - -	virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; - -	virtual MainLoop *get_main_loop() const override; - -	virtual String get_config_path() const override; -	virtual String get_data_path() const override; -	virtual String get_cache_path() const override; -	virtual String get_bundle_resource_dir() const override; -	virtual String get_bundle_icon_path() const override; -	virtual String get_godot_dir_name() const override; - -	virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override; - -	virtual Error shell_open(String p_uri) override; - -	virtual String get_locale() const override; - -	virtual String get_executable_path() const override; -	virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; -	virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; - -	virtual String get_unique_id() const override; -	virtual String get_processor_name() const override; - -	virtual bool _check_internal_feature_support(const String &p_feature) override; - -	virtual void disable_crash_handler() override; -	virtual bool is_disable_crash_handler() const override; - -	virtual Error move_to_trash(const String &p_path) override; - -	void run(); - -	OS_OSX(); -	~OS_OSX(); -}; - -#endif diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm deleted file mode 100644 index 5230ed4155..0000000000 --- a/platform/osx/os_osx.mm +++ /dev/null @@ -1,524 +0,0 @@ -/*************************************************************************/ -/*  os_osx.mm                                                            */ -/*************************************************************************/ -/*                       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 "os_osx.h" - -#include "core/version_generated.gen.h" -#include "main/main.h" - -#include "dir_access_osx.h" -#include "display_server_osx.h" -#include "godot_application.h" -#include "godot_application_delegate.h" -#include "osx_terminal_logger.h" - -#include <dlfcn.h> -#include <libproc.h> -#include <mach-o/dyld.h> -#include <os/log.h> -#include <sys/sysctl.h> - -_FORCE_INLINE_ String OS_OSX::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()))) { -		return p_path.plus_file(p_path.get_file().get_basename()); -	} else { -		return p_path; -	} -} - -void OS_OSX::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(); -	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. -			Main::iteration(); -		} -	} - -	CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Prevent main loop from sleeping. -} - -void OS_OSX::initialize() { -	crash_handler.initialize(); - -	initialize_core(); -} - -String OS_OSX::get_processor_name() const { -	char buffer[256]; -	size_t buffer_len = 256; -	if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, NULL, 0) == 0) { -		return String::utf8(buffer, buffer_len); -	} -	ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string.")); -} - -void OS_OSX::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); -} - -void OS_OSX::finalize() { -#ifdef COREMIDI_ENABLED -	midi_driver.close(); -#endif - -	delete_main_loop(); - -	if (joypad_osx) { -		memdelete(joypad_osx); -	} -} - -void OS_OSX::initialize_joypads() { -	joypad_osx = memnew(JoypadOSX(Input::get_singleton())); -} - -void OS_OSX::set_main_loop(MainLoop *p_main_loop) { -	main_loop = p_main_loop; -} - -void OS_OSX::delete_main_loop() { -	if (!main_loop) { -		return; -	} - -	memdelete(main_loop); -	main_loop = nullptr; -} - -void OS_OSX::set_cmdline_platform_args(const List<String> &p_args) { -	launch_service_args = p_args; -} - -List<String> OS_OSX::get_cmdline_platform_args() const { -	return launch_service_args; -} - -String OS_OSX::get_name() const { -	return "macOS"; -} - -void OS_OSX::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()]; - -	[window addButtonWithTitle:@"OK"]; -	[window setMessageText:ns_title]; -	[window setInformativeText:ns_alert]; -	[window setAlertStyle:NSAlertStyleWarning]; - -	id key_window = [[NSApplication sharedApplication] keyWindow]; -	[window runModal]; -	if (key_window) { -		[key_window makeKeyAndOrderFront:nil]; -	} -} - -Error OS_OSX::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)) { -		// Load .dylib or framework from within the executable path. -		path = get_framework_executable(get_executable_path().get_base_dir().plus_file(p_path.get_file())); -	} - -	if (!FileAccess::exists(path)) { -		// Load .dylib or framework from a standard macOS location. -		path = get_framework_executable(get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file())); -	} - -	p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); -	ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + "."); - -	if (r_resolved_path != nullptr) { -		*r_resolved_path = path; -	} - -	return OK; -} - -MainLoop *OS_OSX::get_main_loop() const { -	return main_loop; -} - -String OS_OSX::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()) { -			return get_environment("XDG_CONFIG_HOME"); -		} else { -			WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/Library/Application Support` or `.` per the XDG Base Directory specification."); -		} -	} -	if (has_environment("HOME")) { -		return get_environment("HOME").plus_file("Library/Application Support"); -	} -	return "."; -} - -String OS_OSX::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()) { -			return get_environment("XDG_DATA_HOME"); -		} else { -			WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `get_config_path()` per the XDG Base Directory specification."); -		} -	} -	return get_config_path(); -} - -String OS_OSX::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()) { -			return get_environment("XDG_CACHE_HOME"); -		} else { -			WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/Library/Caches` or `get_config_path()` per the XDG Base Directory specification."); -		} -	} -	if (has_environment("HOME")) { -		return get_environment("HOME").plus_file("Library/Caches"); -	} -	return get_config_path(); -} - -String OS_OSX::get_bundle_resource_dir() const { -	String ret; - -	NSBundle *main = [NSBundle mainBundle]; -	if (main) { -		NSString *resource_path = [main resourcePath]; -		ret.parse_utf8([resource_path UTF8String]); -	} -	return ret; -} - -String OS_OSX::get_bundle_icon_path() const { -	String ret; - -	NSBundle *main = [NSBundle mainBundle]; -	if (main) { -		NSString *icon_path = [[main infoDictionary] objectForKey:@"CFBundleIconFile"]; -		if (icon_path) { -			ret.parse_utf8([icon_path UTF8String]); -		} -	} -	return ret; -} - -// Get properly capitalized engine name for system paths -String OS_OSX::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 { -	NSSearchPathDirectory id; -	bool found = true; - -	switch (p_dir) { -		case SYSTEM_DIR_DESKTOP: { -			id = NSDesktopDirectory; -		} break; -		case SYSTEM_DIR_DOCUMENTS: { -			id = NSDocumentDirectory; -		} break; -		case SYSTEM_DIR_DOWNLOADS: { -			id = NSDownloadsDirectory; -		} break; -		case SYSTEM_DIR_MOVIES: { -			id = NSMoviesDirectory; -		} break; -		case SYSTEM_DIR_MUSIC: { -			id = NSMusicDirectory; -		} break; -		case SYSTEM_DIR_PICTURES: { -			id = NSPicturesDirectory; -		} break; -		default: { -			found = false; -		} -	} - -	String ret; -	if (found) { -		NSArray *paths = NSSearchPathForDirectoriesInDomains(id, NSUserDomainMask, YES); -		if (paths && [paths count] >= 1) { -			ret.parse_utf8([[paths firstObject] UTF8String]); -		} -	} - -	return ret; -} - -Error OS_OSX::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 -	if (!uri || !uri.scheme || [uri.scheme isEqual:@"file"]) { -		uri = [[NSURL alloc] initWithString:[string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]; -	} -	[[NSWorkspace sharedWorkspace] openURL:uri]; -	return OK; -} - -String OS_OSX::get_locale() const { -	NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0]; -	return String([locale_code UTF8String]).replace("-", "_"); -} - -String OS_OSX::get_executable_path() const { -	char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; -	int pid = getpid(); -	pid_t ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf)); -	if (ret <= 0) { -		return OS::get_executable_path(); -	} else { -		String path; -		path.parse_utf8(pathbuf); - -		return path; -	} -} - -Error OS_OSX::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]; -	if (bundle) { -		NSMutableArray *arguments = [[NSMutableArray alloc] init]; -		for (const String &arg : p_arguments) { -			[arguments addObject:[NSString stringWithUTF8String:arg.utf8().get_data()]]; -		} -		if (@available(macOS 10.15, *)) { -			NSWorkspaceOpenConfiguration *configuration = [[NSWorkspaceOpenConfiguration alloc] init]; -			[configuration setArguments:arguments]; -			[configuration setCreatesNewApplicationInstance:YES]; -			__block dispatch_semaphore_t lock = dispatch_semaphore_create(0); -			__block Error err = ERR_TIMEOUT; -			__block pid_t pid = 0; - -			[[NSWorkspace sharedWorkspace] openApplicationAtURL:url -												  configuration:configuration -											  completionHandler:^(NSRunningApplication *app, NSError *error) { -												  if (error) { -													  err = ERR_CANT_FORK; -													  NSLog(@"Failed to execute: %@", error.localizedDescription); -												  } else { -													  pid = [app processIdentifier]; -													  err = OK; -												  } -												  dispatch_semaphore_signal(lock); -											  }]; -			dispatch_semaphore_wait(lock, dispatch_time(DISPATCH_TIME_NOW, 20000000000)); // 20 sec timeout, wait for app to launch. - -			if (err == OK) { -				if (r_child_id) { -					*r_child_id = (ProcessID)pid; -				} -			} - -			return err; -		} else { -			Error err = ERR_TIMEOUT; -			NSError *error = nullptr; -			NSRunningApplication *app = [[NSWorkspace sharedWorkspace] launchApplicationAtURL:url options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:&error]; -			if (error) { -				err = ERR_CANT_FORK; -				NSLog(@"Failed to execute: %@", error.localizedDescription); -			} else { -				if (r_child_id) { -					*r_child_id = (ProcessID)[app processIdentifier]; -				} -				err = OK; -			} -			return err; -		} -	} else { -		return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console); -	} -} - -Error OS_OSX::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) { -		String path; -		path.parse_utf8([[[NSBundle mainBundle] bundlePath] UTF8String]); -		return create_process(path, p_arguments, r_child_id, false); -	} else { -		return create_process(get_executable_path(), p_arguments, r_child_id, false); -	} -} - -String OS_OSX::get_unique_id() const { -	static String serial_number; - -	if (serial_number.is_empty()) { -		io_service_t platform_expert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); -		CFStringRef serial_number_cf_string = nullptr; -		if (platform_expert) { -			serial_number_cf_string = (CFStringRef)IORegistryEntryCreateCFProperty(platform_expert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0); -			IOObjectRelease(platform_expert); -		} - -		NSString *serial_number_ns_string = nil; -		if (serial_number_cf_string) { -			serial_number_ns_string = [NSString stringWithString:(__bridge NSString *)serial_number_cf_string]; -			CFRelease(serial_number_cf_string); -		} - -		if (serial_number_ns_string) { -			serial_number.parse_utf8([serial_number_ns_string UTF8String]); -		} -	} - -	return serial_number; -} - -bool OS_OSX::_check_internal_feature_support(const String &p_feature) { -	return p_feature == "pc"; -} - -void OS_OSX::disable_crash_handler() { -	crash_handler.disable(); -} - -bool OS_OSX::is_disable_crash_handler() const { -	return crash_handler.is_disabled(); -} - -Error OS_OSX::move_to_trash(const String &p_path) { -	NSFileManager *fm = [NSFileManager defaultManager]; -	NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())]; -	NSError *err; - -	if (![fm trashItemAtURL:url resultingItemURL:nil error:&err]) { -		ERR_PRINT("trashItemAtURL error: " + String::utf8(err.localizedDescription.UTF8String)); -		return FAILED; -	} - -	return OK; -} - -void OS_OSX::run() { -	force_quit = false; - -	if (!main_loop) { -		return; -	} - -	main_loop->initialize(); - -	bool quit = false; -	while (!force_quit && !quit) { -		@try { -			if (DisplayServer::get_singleton()) { -				DisplayServer::get_singleton()->process_events(); // Get rid of pending events. -			} -			joypad_osx->process_joypads(); - -			if (Main::iteration()) { -				quit = true; -			} -		} @catch (NSException *exception) { -			ERR_PRINT("NSException: " + String::utf8([exception reason].UTF8String)); -		} -	} - -	main_loop->finalize(); -} - -OS_OSX::OS_OSX() { -	main_loop = nullptr; -	force_quit = false; - -	Vector<Logger *> loggers; -	loggers.push_back(memnew(OSXTerminalLogger)); -	_set_logger(memnew(CompositeLogger(loggers))); - -#ifdef COREAUDIO_ENABLED -	AudioDriverManager::add_driver(&audio_driver); -#endif - -	DisplayServerOSX::register_osx_driver(); - -	// Implicitly create shared NSApplication instance. -	[GodotApplication sharedApplication]; - -	// In case we are unbundled, make us a proper UI application. -	[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - -	// Menu bar setup must go between sharedApplication above and -	// finishLaunching below, in order to properly emulate the behavior -	// of NSApplicationMain. - -	NSMenu *main_menu = [[NSMenu alloc] initWithTitle:@""]; -	[NSApp setMainMenu:main_menu]; -	[NSApp finishLaunching]; - -	id delegate = [[GodotApplicationDelegate alloc] init]; -	ERR_FAIL_COND(!delegate); -	[NSApp setDelegate:delegate]; - -	pre_wait_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, &pre_wait_observer_cb, nullptr); -	CFRunLoopAddObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); - -	// Process application:openFile: event. -	while (true) { -		NSEvent *event = [NSApp -				nextEventMatchingMask:NSEventMaskAny -							untilDate:[NSDate distantPast] -							   inMode:NSDefaultRunLoopMode -							  dequeue:YES]; - -		if (event == nil) { -			break; -		} - -		[NSApp sendEvent:event]; -	} - -	[NSApp activateIgnoringOtherApps:YES]; -} - -OS_OSX::~OS_OSX() { -	CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); -	CFRelease(pre_wait_observer); -} diff --git a/platform/osx/osx_terminal_logger.h b/platform/osx/osx_terminal_logger.h deleted file mode 100644 index 8413509c4b..0000000000 --- a/platform/osx/osx_terminal_logger.h +++ /dev/null @@ -1,44 +0,0 @@ -/*************************************************************************/ -/*  osx_terminal_logger.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 OSX_TERMINAL_LOGGER_H -#define OSX_TERMINAL_LOGGER_H - -#ifdef OSX_ENABLED - -#include "core/io/logger.h" - -class OSXTerminalLogger : 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 diff --git a/platform/osx/osx_terminal_logger.mm b/platform/osx/osx_terminal_logger.mm deleted file mode 100644 index 48e26f42bf..0000000000 --- a/platform/osx/osx_terminal_logger.mm +++ /dev/null @@ -1,82 +0,0 @@ -/*************************************************************************/ -/*  osx_terminal_logger.mm                                               */ -/*************************************************************************/ -/*                       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 "osx_terminal_logger.h" - -#ifdef OSX_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) { -	if (!should_log(true)) { -		return; -	} - -	const char *err_details; -	if (p_rationale && p_rationale[0]) { -		err_details = p_rationale; -	} else { -		err_details = p_code; -	} - -	switch (p_type) { -		case ERR_WARNING: -			os_log_info(OS_LOG_DEFAULT, -					"WARNING: %{public}s\nat: %{public}s (%{public}s:%i)", -					err_details, p_function, p_file, p_line); -			logf_error("\E[1;33mWARNING:\E[0;93m %s\n", err_details); -			logf_error("\E[0;90m     at: %s (%s:%i)\E[0m\n", p_function, p_file, p_line); -			break; -		case ERR_SCRIPT: -			os_log_error(OS_LOG_DEFAULT, -					"SCRIPT ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", -					err_details, p_function, p_file, p_line); -			logf_error("\E[1;35mSCRIPT ERROR:\E[0;95m %s\n", err_details); -			logf_error("\E[0;90m          at: %s (%s:%i)\E[0m\n", p_function, p_file, p_line); -			break; -		case ERR_SHADER: -			os_log_error(OS_LOG_DEFAULT, -					"SHADER ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", -					err_details, p_function, p_file, p_line); -			logf_error("\E[1;36mSHADER ERROR:\E[0;96m %s\n", err_details); -			logf_error("\E[0;90m          at: %s (%s:%i)\E[0m\n", p_function, p_file, p_line); -			break; -		case ERR_ERROR: -		default: -			os_log_error(OS_LOG_DEFAULT, -					"ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", -					err_details, p_function, p_file, p_line); -			logf_error("\E[1;31mERROR:\E[0;91m %s\n", err_details); -			logf_error("\E[0;90m   at: %s (%s:%i)\E[0m\n", p_function, p_file, p_line); -			break; -	} -} - -#endif // OSX_ENABLED diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h deleted file mode 100644 index e114606b82..0000000000 --- a/platform/osx/platform_config.h +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************/ -/*  platform_config.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.                */ -/*************************************************************************/ - -#include <alloca.h> - -#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h" -#define PTHREAD_RENAME_SELF diff --git a/platform/osx/platform_osx_builders.py b/platform/osx/platform_osx_builders.py deleted file mode 100644 index 953ed479db..0000000000 --- a/platform/osx/platform_osx_builders.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Functions used to generate source files during build time - -All such functions are invoked in a subprocess on Windows to prevent build flakiness. - -""" -import os -from platform_methods import subprocess_main - - -def make_debug_osx(target, source, env): -    if env["macports_clang"] != "no": -        mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") -        mpclangver = env["macports_clang"] -        os.system(mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-dsymutil {0} -o {0}.dSYM".format(target[0])) -    else: -        os.system("dsymutil {0} -o {0}.dSYM".format(target[0])) -    os.system("strip -u -r {0}".format(target[0])) - - -if __name__ == "__main__": -    subprocess_main(globals()) diff --git a/platform/osx/tts_osx.h b/platform/osx/tts_osx.h deleted file mode 100644 index 449418e48f..0000000000 --- a/platform/osx/tts_osx.h +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************/ -/*  tts_osx.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 TTS_OSX_H -#define TTS_OSX_H - -#include "core/string/ustring.h" -#include "core/templates/list.h" -#include "core/templates/rb_map.h" -#include "core/variant/array.h" -#include "servers/display_server.h" - -#import <AppKit/AppKit.h> - -#if __has_include(<AVFAudio/AVSpeechSynthesis.h>) -#import <AVFAudio/AVSpeechSynthesis.h> -#else -#import <AVFoundation/AVFoundation.h> -#endif - -@interface TTS_OSX : NSObject <AVSpeechSynthesizerDelegate> { -	// AVSpeechSynthesizer -	bool speaking; -	HashMap<id, int> ids; - -	// NSSpeechSynthesizer -	bool paused; -	bool have_utterance; -	int last_utterance; - -	id synth; // NSSpeechSynthesizer or AVSpeechSynthesizer -	List<DisplayServer::TTSUtterance> queue; -} - -- (void)pauseSpeaking; -- (void)resumeSpeaking; -- (void)stopSpeaking; -- (bool)isSpeaking; -- (bool)isPaused; -- (void)speak:(const String &)text voice:(const String &)voice volume:(int)volume pitch:(float)pitch rate:(float)rate utterance_id:(int)utterance_id interrupt:(bool)interrupt; -- (Array)getVoices; -@end - -#endif // TTS_OSX_H diff --git a/platform/osx/tts_osx.mm b/platform/osx/tts_osx.mm deleted file mode 100644 index e6a5236cd9..0000000000 --- a/platform/osx/tts_osx.mm +++ /dev/null @@ -1,266 +0,0 @@ -/*************************************************************************/ -/*  tts_osx.mm                                                           */ -/*************************************************************************/ -/*                       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 "tts_osx.h" - -@implementation TTS_OSX - -- (id)init { -	self = [super init]; -	self->speaking = false; -	self->have_utterance = false; -	self->last_utterance = -1; -	self->paused = false; -	if (@available(macOS 10.14, *)) { -		self->synth = [[AVSpeechSynthesizer alloc] init]; -		[self->synth setDelegate:self]; -		print_verbose("Text-to-Speech: AVSpeechSynthesizer initialized."); -	} else { -		self->synth = [[NSSpeechSynthesizer alloc] init]; -		[self->synth setDelegate:self]; -		print_verbose("Text-to-Speech: NSSpeechSynthesizer initialized."); -	} -	return self; -} - -// AVSpeechSynthesizer callback (macOS 10.14+) - -- (void)speechSynthesizer:(AVSpeechSynthesizer *)av_synth willSpeakRangeOfSpeechString:(NSRange)characterRange utterance:(AVSpeechUtterance *)utterance API_AVAILABLE(macosx(10.14)) { -	NSString *string = [utterance speechString]; - -	// Convert from UTF-16 to UTF-32 position. -	int pos = 0; -	for (NSUInteger i = 0; i < MIN(characterRange.location, string.length); i++) { -		unichar c = [string characterAtIndex:i]; -		if ((c & 0xfffffc00) == 0xd800) { -			i++; -		} -		pos++; -	} - -	DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_BOUNDARY, ids[utterance], pos); -} - -// AVSpeechSynthesizer callback (macOS 10.14+) - -- (void)speechSynthesizer:(AVSpeechSynthesizer *)av_synth didCancelSpeechUtterance:(AVSpeechUtterance *)utterance API_AVAILABLE(macosx(10.14)) { -	DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, ids[utterance]); -	ids.erase(utterance); -	speaking = false; -	[self update]; -} - -// AVSpeechSynthesizer callback (macOS 10.14+) - -- (void)speechSynthesizer:(AVSpeechSynthesizer *)av_synth didFinishSpeechUtterance:(AVSpeechUtterance *)utterance API_AVAILABLE(macosx(10.14)) { -	DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_ENDED, ids[utterance]); -	ids.erase(utterance); -	speaking = false; -	[self update]; -} - -// NSSpeechSynthesizer callback (macOS 10.4+) - -- (void)speechSynthesizer:(NSSpeechSynthesizer *)ns_synth willSpeakWord:(NSRange)characterRange ofString:(NSString *)string { -	if (!paused && have_utterance) { -		// Convert from UTF-16 to UTF-32 position. -		int pos = 0; -		for (NSUInteger i = 0; i < MIN(characterRange.location, string.length); i++) { -			unichar c = [string characterAtIndex:i]; -			if ((c & 0xfffffc00) == 0xd800) { -				i++; -			} -			pos++; -		} - -		DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_BOUNDARY, last_utterance, pos); -	} -} - -- (void)speechSynthesizer:(NSSpeechSynthesizer *)ns_synth didFinishSpeaking:(BOOL)success { -	if (!paused && have_utterance) { -		if (success) { -			DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_ENDED, last_utterance); -		} else { -			DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, last_utterance); -		} -		have_utterance = false; -	} -	speaking = false; -	[self update]; -} - -- (void)update { -	if (!speaking && queue.size() > 0) { -		DisplayServer::TTSUtterance &message = queue.front()->get(); - -		if (@available(macOS 10.14, *)) { -			AVSpeechSynthesizer *av_synth = synth; -			AVSpeechUtterance *new_utterance = [[AVSpeechUtterance alloc] initWithString:[NSString stringWithUTF8String:message.text.utf8().get_data()]]; -			[new_utterance setVoice:[AVSpeechSynthesisVoice voiceWithIdentifier:[NSString stringWithUTF8String:message.voice.utf8().get_data()]]]; -			if (message.rate > 1.f) { -				[new_utterance setRate:Math::range_lerp(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)]; -			} else if (message.rate < 1.f) { -				[new_utterance setRate:Math::range_lerp(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)]; -			} -			[new_utterance setPitchMultiplier:message.pitch]; -			[new_utterance setVolume:(Math::range_lerp(message.volume, 0.f, 100.f, 0.f, 1.f))]; - -			ids[new_utterance] = message.id; -			[av_synth speakUtterance:new_utterance]; -		} else { -			NSSpeechSynthesizer *ns_synth = synth; -			[ns_synth setObject:nil forProperty:NSSpeechResetProperty error:nil]; -			[ns_synth setVoice:[NSString stringWithUTF8String:message.voice.utf8().get_data()]]; -			int base_pitch = [[ns_synth objectForProperty:NSSpeechPitchBaseProperty error:nil] intValue]; -			[ns_synth setObject:[NSNumber numberWithInt:(base_pitch * (message.pitch / 2.f + 0.5f))] forProperty:NSSpeechPitchBaseProperty error:nullptr]; -			[ns_synth setVolume:(Math::range_lerp(message.volume, 0.f, 100.f, 0.f, 1.f))]; -			[ns_synth setRate:(message.rate * 200)]; - -			last_utterance = message.id; -			have_utterance = true; -			[ns_synth startSpeakingString:[NSString stringWithUTF8String:message.text.utf8().get_data()]]; -		} -		queue.pop_front(); - -		DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_STARTED, message.id); -		speaking = true; -	} -} - -- (void)pauseSpeaking { -	if (@available(macOS 10.14, *)) { -		AVSpeechSynthesizer *av_synth = synth; -		[av_synth pauseSpeakingAtBoundary:AVSpeechBoundaryImmediate]; -	} else { -		NSSpeechSynthesizer *ns_synth = synth; -		[ns_synth pauseSpeakingAtBoundary:NSSpeechImmediateBoundary]; -	} -	paused = true; -} - -- (void)resumeSpeaking { -	if (@available(macOS 10.14, *)) { -		AVSpeechSynthesizer *av_synth = synth; -		[av_synth continueSpeaking]; -	} else { -		NSSpeechSynthesizer *ns_synth = synth; -		[ns_synth continueSpeaking]; -	} -	paused = false; -} - -- (void)stopSpeaking { -	for (DisplayServer::TTSUtterance &message : queue) { -		DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, message.id); -	} -	queue.clear(); -	if (@available(macOS 10.14, *)) { -		AVSpeechSynthesizer *av_synth = synth; -		[av_synth stopSpeakingAtBoundary:AVSpeechBoundaryImmediate]; -	} else { -		NSSpeechSynthesizer *ns_synth = synth; -		if (have_utterance) { -			DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, last_utterance); -		} -		[ns_synth stopSpeaking]; -	} -	have_utterance = false; -	speaking = false; -	paused = false; -} - -- (bool)isSpeaking { -	return speaking || (queue.size() > 0); -} - -- (bool)isPaused { -	if (@available(macOS 10.14, *)) { -		AVSpeechSynthesizer *av_synth = synth; -		return [av_synth isPaused]; -	} else { -		return paused; -	} -} - -- (void)speak:(const String &)text voice:(const String &)voice volume:(int)volume pitch:(float)pitch rate:(float)rate utterance_id:(int)utterance_id interrupt:(bool)interrupt { -	if (interrupt) { -		[self stopSpeaking]; -	} - -	if (text.is_empty()) { -		DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, utterance_id); -		return; -	} - -	DisplayServer::TTSUtterance message; -	message.text = text; -	message.voice = voice; -	message.volume = CLAMP(volume, 0, 100); -	message.pitch = CLAMP(pitch, 0.f, 2.f); -	message.rate = CLAMP(rate, 0.1f, 10.f); -	message.id = utterance_id; -	queue.push_back(message); - -	if ([self isPaused]) { -		[self resumeSpeaking]; -	} else { -		[self update]; -	} -} - -- (Array)getVoices { -	Array list; -	if (@available(macOS 10.14, *)) { -		for (AVSpeechSynthesisVoice *voice in [AVSpeechSynthesisVoice speechVoices]) { -			NSString *voiceIdentifierString = [voice identifier]; -			NSString *voiceLocaleIdentifier = [voice language]; -			NSString *voiceName = [voice name]; -			Dictionary voice_d; -			voice_d["name"] = String::utf8([voiceName UTF8String]); -			voice_d["id"] = String::utf8([voiceIdentifierString UTF8String]); -			voice_d["language"] = String::utf8([voiceLocaleIdentifier UTF8String]); -			list.push_back(voice_d); -		} -	} else { -		for (NSString *voiceIdentifierString in [NSSpeechSynthesizer availableVoices]) { -			NSString *voiceLocaleIdentifier = [[NSSpeechSynthesizer attributesForVoice:voiceIdentifierString] objectForKey:NSVoiceLocaleIdentifier]; -			NSString *voiceName = [[NSSpeechSynthesizer attributesForVoice:voiceIdentifierString] objectForKey:NSVoiceName]; -			Dictionary voice_d; -			voice_d["name"] = String([voiceName UTF8String]); -			voice_d["id"] = String([voiceIdentifierString UTF8String]); -			voice_d["language"] = String([voiceLocaleIdentifier UTF8String]); -			list.push_back(voice_d); -		} -	} -	return list; -} - -@end diff --git a/platform/osx/vulkan_context_osx.h b/platform/osx/vulkan_context_osx.h deleted file mode 100644 index ade0f4a4c9..0000000000 --- a/platform/osx/vulkan_context_osx.h +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************/ -/*  vulkan_context_osx.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 VULKAN_DEVICE_OSX_H -#define VULKAN_DEVICE_OSX_H - -#include "drivers/vulkan/vulkan_context.h" -#import <AppKit/AppKit.h> - -class VulkanContextOSX : 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(); -}; - -#endif // VULKAN_DEVICE_OSX_H diff --git a/platform/osx/vulkan_context_osx.mm b/platform/osx/vulkan_context_osx.mm deleted file mode 100644 index bdabc24c28..0000000000 --- a/platform/osx/vulkan_context_osx.mm +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/*  vulkan_context_osx.mm                                                */ -/*************************************************************************/ -/*                       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 "vulkan_context_osx.h" -#ifdef USE_VOLK -#include <volk.h> -#else -#include <vulkan/vulkan.h> -#endif - -const char *VulkanContextOSX::_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) { -	VkMacOSSurfaceCreateInfoMVK createInfo; -	createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; -	createInfo.pNext = nullptr; -	createInfo.flags = 0; -	createInfo.pView = (__bridge const void *)p_window; - -	VkSurfaceKHR surface; -	VkResult err = vkCreateMacOSSurfaceMVK(get_instance(), &createInfo, nullptr, &surface); -	ERR_FAIL_COND_V(err, ERR_CANT_CREATE); -	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); -} - -VulkanContextOSX::VulkanContextOSX() { -} - -VulkanContextOSX::~VulkanContextOSX() { -}  |