summaryrefslogtreecommitdiff
path: root/platform/osx
diff options
context:
space:
mode:
Diffstat (limited to 'platform/osx')
-rw-r--r--platform/osx/SCsub30
-rw-r--r--platform/osx/crash_handler_osx.h47
-rw-r--r--platform/osx/crash_handler_osx.mm203
-rw-r--r--platform/osx/detect.py251
-rw-r--r--platform/osx/dir_access_osx.h55
-rw-r--r--platform/osx/dir_access_osx.mm81
-rw-r--r--platform/osx/display_server_osx.h406
-rw-r--r--platform/osx/display_server_osx.mm3304
-rw-r--r--platform/osx/export/codesign.cpp1564
-rw-r--r--platform/osx/export/codesign.h368
-rw-r--r--platform/osx/export/export.cpp43
-rw-r--r--platform/osx/export/export.h36
-rw-r--r--platform/osx/export/export_plugin.cpp1673
-rw-r--r--platform/osx/export/export_plugin.h137
-rw-r--r--platform/osx/export/lipo.cpp236
-rw-r--r--platform/osx/export/lipo.h76
-rw-r--r--platform/osx/export/macho.cpp548
-rw-r--r--platform/osx/export/macho.h215
-rw-r--r--platform/osx/export/plist.cpp570
-rw-r--r--platform/osx/export/plist.h116
-rw-r--r--platform/osx/gl_manager_osx_legacy.h97
-rw-r--r--platform/osx/gl_manager_osx_legacy.mm228
-rw-r--r--platform/osx/godot_application.h42
-rw-r--r--platform/osx/godot_application.mm58
-rw-r--r--platform/osx/godot_application_delegate.h46
-rw-r--r--platform/osx/godot_application_delegate.mm163
-rw-r--r--platform/osx/godot_content_view.h66
-rw-r--r--platform/osx/godot_content_view.mm771
-rw-r--r--platform/osx/godot_main_osx.mm92
-rw-r--r--platform/osx/godot_menu_item.h61
-rw-r--r--platform/osx/godot_window.h47
-rw-r--r--platform/osx/godot_window.mm69
-rw-r--r--platform/osx/godot_window_delegate.h47
-rw-r--r--platform/osx/godot_window_delegate.mm270
-rw-r--r--platform/osx/joypad_osx.cpp616
-rw-r--r--platform/osx/joypad_osx.h124
-rw-r--r--platform/osx/key_mapping_osx.h52
-rw-r--r--platform/osx/key_mapping_osx.mm496
-rw-r--r--platform/osx/logo.pngbin7195 -> 0 bytes
-rw-r--r--platform/osx/os_osx.h120
-rw-r--r--platform/osx/os_osx.mm524
-rw-r--r--platform/osx/osx_terminal_logger.h44
-rw-r--r--platform/osx/osx_terminal_logger.mm82
-rw-r--r--platform/osx/platform_config.h34
-rw-r--r--platform/osx/platform_osx_builders.py21
-rw-r--r--platform/osx/tts_osx.h71
-rw-r--r--platform/osx/tts_osx.mm266
-rw-r--r--platform/osx/vulkan_context_osx.h47
-rw-r--r--platform/osx/vulkan_context_osx.mm59
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(&lt, &t);
-#else
- gmtime_r(&t, &lt);
-#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
deleted file mode 100644
index b5a660b165..0000000000
--- a/platform/osx/logo.png
+++ /dev/null
Binary files differ
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() {
-}