diff options
Diffstat (limited to 'platform/osx')
24 files changed, 0 insertions, 8260 deletions
diff --git a/platform/osx/SCsub b/platform/osx/SCsub deleted file mode 100644 index 8ba106d1c2..0000000000 --- a/platform/osx/SCsub +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -from platform_methods import run_in_subprocess -import platform_osx_builders - -files = [ - "crash_handler_osx.mm", - "os_osx.mm", - "display_server_osx.mm", - "godot_main_osx.mm", - "dir_access_osx.mm", - "joypad_osx.cpp", - "vulkan_context_osx.mm", - "gl_manager_osx.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 1601bbaab6..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-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 57bca7a5b9..0000000000 --- a/platform/osx/crash_handler_osx.mm +++ /dev/null @@ -1,199 +0,0 @@ -/*************************************************************************/ -/* crash_handler_osx.mm */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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/version.h" -#include "core/version_hash.gen.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"); - } - - // Dump the backtrace to stderr with a message to the user - fprintf(stderr, "\n================================================================\n"); - fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); - - if (OS::get_singleton()->get_main_loop()) - OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); - - // Print the engine version just before, so that people are reminded to include the version in backtrace reports. - if (String(VERSION_HASH).length() != 0) { - fprintf(stderr, "Engine version: " VERSION_FULL_NAME " (" VERSION_HASH ")\n"); - } else { - fprintf(stderr, "Engine version: " VERSION_FULL_NAME "\n"); - } - fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data()); - char **strings = backtrace_symbols(bt_buffer, size); - if (strings) { - void *load_addr = (void *)load_address(); - - 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; - } - } - - fprintf(stderr, "[%zu] %s\n", i, output.utf8().get_data()); - } - - free(strings); - } - fprintf(stderr, "-- END OF BACKTRACE --\n"); - fprintf(stderr, "================================================================\n"); - - // 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 c67791b340..0000000000 --- a/platform/osx/detect.py +++ /dev/null @@ -1,195 +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 [] - - -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 10.15+, platform arm64.") - env.Append(CCFLAGS=["-arch", "arm64", "-mmacosx-version-min=10.15"]) - env.Append(LINKFLAGS=["-arch", "arm64", "-mmacosx-version-min=10.15"]) - else: - print("Building for macOS 10.12+, platform x86_64.") - env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) - env.Append(LINKFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) - - 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" - - 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"]) - - 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=["-L$VULKAN_SDK_PATH/MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/", "-lMoltenVK"]) diff --git a/platform/osx/dir_access_osx.h b/platform/osx/dir_access_osx.h deleted file mode 100644 index a894723e64..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-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 552c33d018..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-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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> - -#include <AppKit/NSWorkspace.h> -#include <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 3cc0b10c5b..0000000000 --- a/platform/osx/display_server_osx.h +++ /dev/null @@ -1,329 +0,0 @@ -/*************************************************************************/ -/* display_server_osx.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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.h" -#endif - -#if defined(VULKAN_ENABLED) -#include "drivers/vulkan/rendering_device_vulkan.h" -#include "platform/osx/vulkan_context_osx.h" -#endif - -#include <AppKit/AppKit.h> -#include <AppKit/NSCursor.h> -#include <ApplicationServices/ApplicationServices.h> -#include <CoreVideo/CoreVideo.h> - -#undef BitMap -#undef CursorShape - -class DisplayServerOSX : public DisplayServer { - GDCLASS(DisplayServerOSX, DisplayServer) - - _THREAD_SAFE_CLASS_ - -public: - void _send_event(NSEvent *p_event); - NSMenu *_get_dock_menu() const; - void _menu_callback(id p_sender); - -#if defined(GLES3_ENABLED) - GLManager_OSX *gl_manager = nullptr; -#endif -#if defined(VULKAN_ENABLED) - VulkanContextOSX *context_vulkan = nullptr; - RenderingDeviceVulkan *rendering_device_vulkan = nullptr; -#endif - - const NSMenu *_get_menu_root(const String &p_menu_root) const; - NSMenu *_get_menu_root(const String &p_menu_root); - - NSMenu *apple_menu = nullptr; - NSMenu *dock_menu = nullptr; - Map<String, NSMenu *> submenu; - - struct KeyEvent { - WindowID 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 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; - - 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 mouse_down_control = false; - - 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; - Set<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; - }; - - Point2i im_selection; - String im_text; - - Map<WindowID, WindowData> windows; - - WindowID window_id_counter = MAIN_WINDOW_ID; - - WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect); - void _update_window(WindowData p_wd); - void _send_window_event(const WindowData &wd, WindowEvent p_event); - static void _dispatch_input_events(const Ref<InputEvent> &p_event); - void _dispatch_input_event(const Ref<InputEvent> &p_event); - WindowID _find_window_id(id p_window); - - void _set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window); - - Point2i _get_screens_origin() const; - Point2i _get_native_screen_position(int p_screen) const; - - void _push_input(const Ref<InputEvent> &p_event); - void _process_key_events(); - void _release_pressed_events(); - - String rendering_driver; - - id autoreleasePool; - CGEventSourceRef eventSource; - - CursorShape cursor_shape; - NSCursor *cursors[CURSOR_MAX]; - Map<CursorShape, Vector<Variant>> cursors_cache; - - MouseMode mouse_mode; - Point2i last_mouse_pos; - MouseButton last_button_state = MouseButton::NONE; - - bool window_focused; - bool drop_events; - bool in_dispatch_input_event = false; - -public: - 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, const Variant &p_tag = Variant()) override; - virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag = Variant()) override; - virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu) override; - virtual void global_menu_add_separator(const String &p_menu_root) 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 Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx) override; - virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx) override; - virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx) override; - virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx) 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_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 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 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; - - virtual void mouse_warp_to_position(const Point2i &p_to) override; - virtual Point2i mouse_get_position() const override; - virtual Point2i mouse_get_absolute_position() const override; - 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 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 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_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 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; - - virtual void cursor_set_shape(CursorShape p_shape) override; - virtual CursorShape cursor_get_shape() const override; - virtual void cursor_set_custom_image(const RES &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; - - virtual void console_set_visible(bool p_enabled) override; - virtual bool is_console_visible() const 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 fec5c98a99..0000000000 --- a/platform/osx/display_server_osx.mm +++ /dev/null @@ -1,3870 +0,0 @@ -/*************************************************************************/ -/* display_server_osx.mm */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 "os_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" - -#include <Carbon/Carbon.h> -#include <Cocoa/Cocoa.h> -#include <IOKit/IOCFPlugIn.h> -#include <IOKit/IOKitLib.h> -#include <IOKit/hid/IOHIDKeys.h> -#include <IOKit/hid/IOHIDLib.h> - -#if defined(GLES3_ENABLED) -#include "drivers/gles3/rasterizer_gles3.h" - -#import <AppKit/NSOpenGLView.h> -#endif - -#if defined(VULKAN_ENABLED) -#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" - -#include <QuartzCore/CAMetalLayer.h> -#endif - -#ifndef NSAppKitVersionNumber10_14 -#define NSAppKitVersionNumber10_14 1671 -#endif - -#define DS_OSX ((DisplayServerOSX *)(DisplayServerOSX::get_singleton())) - -static bool ignore_momentum_scroll = false; - -static void _get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) { - 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)); -} - -static Vector2i _get_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPoint p_locationInWindow) { - const NSRect contentRect = [p_wd.window_view frame]; - const float scale = DS_OSX->screen_get_max_scale(); - p_wd.mouse_pos.x = p_locationInWindow.x * scale; - p_wd.mouse_pos.y = (contentRect.size.height - p_locationInWindow.y) * scale; - DS_OSX->last_mouse_pos = p_wd.mouse_pos; - Input::get_singleton()->set_mouse_position(p_wd.mouse_pos); - return p_wd.mouse_pos; -} - -static void _push_to_key_event_buffer(const DisplayServerOSX::KeyEvent &p_event) { - Vector<DisplayServerOSX::KeyEvent> &buffer = DS_OSX->key_event_buffer; - if (DS_OSX->key_event_pos >= buffer.size()) { - buffer.resize(1 + DS_OSX->key_event_pos); - } - buffer.write[DS_OSX->key_event_pos++] = p_event; -} - -static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { - if ([NSCursor respondsToSelector:selector]) { - id object = [NSCursor performSelector:selector]; - if ([object isKindOfClass:[NSCursor class]]) { - return object; - } - } - if (fallback) { - // Fallback should be a reasonable default, no need to check. - return [NSCursor performSelector:fallback]; - } - return [NSCursor arrowCursor]; -} - -/*************************************************************************/ -/* GlobalMenuItem */ -/*************************************************************************/ - -@interface GlobalMenuItem : NSObject { -@public - Callable callback; - Variant meta; - bool checkable; -} - -@end - -@implementation GlobalMenuItem -@end - -/*************************************************************************/ -/* GodotWindowDelegate */ -/*************************************************************************/ - -@interface GodotWindowDelegate : NSObject { - DisplayServerOSX::WindowID window_id; -} - -- (void)windowWillClose:(NSNotification *)notification; -- (void)setWindowID:(DisplayServerOSX::WindowID)wid; - -@end - -@implementation GodotWindowDelegate - -- (void)setWindowID:(DisplayServerOSX::WindowID)wid { - window_id = wid; -} - -- (BOOL)windowShouldClose:(id)sender { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return YES; - } - DS_OSX->_send_window_event(DS_OSX->windows[window_id], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); - return NO; -} - -- (void)windowWillClose:(NSNotification *)notification { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - while (wd.transient_children.size()) { - DS_OSX->window_set_transient(wd.transient_children.front()->get(), DisplayServerOSX::INVALID_WINDOW_ID); - } - - if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) { - DisplayServerOSX::WindowData &pwd = DS_OSX->windows[wd.transient_parent]; - [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to parent. - DS_OSX->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID); - } else if ((window_id != DisplayServerOSX::MAIN_WINDOW_ID) && (DS_OSX->windows.size() == 1)) { - DisplayServerOSX::WindowData &pwd = DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID]; - [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to main window if there is no parent or other windows left. - } - -#if defined(GLES3_ENABLED) - if (DS_OSX->rendering_driver == "opengl3") { - DS_OSX->gl_manager->window_destroy(window_id); - } -#endif -#ifdef VULKAN_ENABLED - if (DS_OSX->rendering_driver == "vulkan") { - DS_OSX->context_vulkan->window_destroy(window_id); - } -#endif - - DS_OSX->windows.erase(window_id); -} - -- (void)windowDidEnterFullScreen:(NSNotification *)notification { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - wd.fullscreen = true; - - [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 { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - wd.fullscreen = false; - - const float scale = DS_OSX->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)]; - } - - if (wd.resize_disabled) { - [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable]; - } - - if (wd.on_top) { - [wd.window_object setLevel:NSFloatingWindowLevel]; - } - // Force window resize event. - [self windowDidResize:notification]; -} - -- (void)windowDidChangeBackingProperties:(NSNotification *)notification { - if (!DisplayServerOSX::get_singleton()) { - return; - } - - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - CGFloat newBackingScaleFactor = [wd.window_object backingScaleFactor]; - CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; - - if (newBackingScaleFactor != oldBackingScaleFactor) { - //Set new display scale and window size - const float scale = DS_OSX->screen_get_max_scale(); - const NSRect contentRect = [wd.window_view frame]; - - wd.size.width = contentRect.size.width * scale; - wd.size.height = contentRect.size.height * scale; - - DS_OSX->_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)windowDidResize:(NSNotification *)notification { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - const NSRect contentRect = [wd.window_view frame]; - - const float scale = DS_OSX->screen_get_max_scale(); - wd.size.width = contentRect.size.width * scale; - wd.size.height = contentRect.size.height * scale; - - CALayer *layer = [wd.window_view layer]; - if (layer) { - layer.contentsScale = scale; - } - -#if defined(GLES3_ENABLED) - if (DS_OSX->rendering_driver == "opengl3") { - DS_OSX->gl_manager->window_resize(window_id, wd.size.width, wd.size.height); - } -#endif -#if defined(VULKAN_ENABLED) - if (DS_OSX->rendering_driver == "vulkan") { - DS_OSX->context_vulkan->window_resize(window_id, wd.size.width, wd.size.height); - } -#endif - - if (!wd.rect_changed_callback.is_null()) { - Variant size = Rect2i(DS_OSX->window_get_position(window_id), DS_OSX->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 { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - DS_OSX->_release_pressed_events(); - - if (!wd.rect_changed_callback.is_null()) { - Variant size = Rect2i(DS_OSX->window_get_position(window_id), DS_OSX->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 { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CAPTURED) { - 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 { - _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); - Input::get_singleton()->set_mouse_position(wd.mouse_pos); - } - - DS_OSX->window_focused = true; - DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); -} - -- (void)windowDidResignKey:(NSNotification *)notification { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - DS_OSX->window_focused = false; - - DS_OSX->_release_pressed_events(); - DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT); -} - -- (void)windowDidMiniaturize:(NSNotification *)notification { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - DS_OSX->window_focused = false; - - DS_OSX->_release_pressed_events(); - DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT); -} - -- (void)windowDidDeminiaturize:(NSNotification *)notification { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) { - return; - } - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - DS_OSX->window_focused = true; - DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); -} - -@end - -/*************************************************************************/ -/* GodotContentView */ -/*************************************************************************/ - -#if defined(GLES3_ENABLED) -@interface GodotContentView : NSOpenGLView <NSTextInputClient> { -#else -@interface GodotContentView : NSView <NSTextInputClient> { -#endif - - DisplayServerOSX::WindowID window_id; - NSTrackingArea *trackingArea; - NSMutableAttributedString *markedText; - bool imeInputEventInProgress; -} - -- (void)cancelComposition; -- (CALayer *)makeBackingLayer; -- (BOOL)wantsUpdateLayer; -- (void)updateLayer; -- (void)setWindowID:(DisplayServerOSX::WindowID)wid; - -@end - -@implementation GodotContentView - -- (void)setWindowID:(DisplayServerOSX::WindowID)wid { - window_id = wid; -} - -+ (void)initialize { - if (self == [GodotContentView class]) { - // nothing left to do here at the moment.. - } -} - -- (CALayer *)makeBackingLayer { -#if defined(VULKAN_ENABLED) - if (DS_OSX->rendering_driver == "vulkan") { - CALayer *layer = [[CAMetalLayer class] layer]; - return layer; - } -#endif - return [super makeBackingLayer]; -} - -- (void)updateLayer { -#if defined(GLES3_ENABLED) - if (DS_OSX->rendering_driver == "opengl3") { - DS_OSX->gl_manager->window_update(window_id); - } -#endif -#if defined(VULKAN_ENABLED) - if (DS_OSX->rendering_driver == "vulkan") { - [super updateLayer]; - } -#endif -} - -- (BOOL)wantsUpdateLayer { - return YES; -} - -- (id)init { - self = [super init]; - trackingArea = nil; - imeInputEventInProgress = false; - [self updateTrackingAreas]; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 - [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]]; -#else - [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]]; -#endif - markedText = [[NSMutableAttributedString alloc] init]; - return self; -} - -- (void)dealloc { - [trackingArea release]; - [markedText release]; - [super dealloc]; -} - -static const NSRange kEmptyRange = { NSNotFound, 0 }; - -- (BOOL)hasMarkedText { - return (markedText.length > 0); -} - -- (NSRange)markedRange { - return NSMakeRange(0, markedText.length); -} - -- (NSRange)selectedRange { - return kEmptyRange; -} - -- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange { - if ([aString isKindOfClass:[NSAttributedString class]]) { - [markedText initWithAttributedString:aString]; - } else { - [markedText initWithString:aString]; - } - if (markedText.length == 0) { - [self unmarkText]; - return; - } - - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (wd.im_active) { - imeInputEventInProgress = true; - DS_OSX->im_text.parse_utf8([[markedText mutableString] UTF8String]); - DS_OSX->im_selection = Point2i(selectedRange.location, selectedRange.length); - - OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE); - } -} - -- (void)doCommandBySelector:(SEL)aSelector { - if ([self respondsToSelector:aSelector]) { - [self performSelector:aSelector]; - } -} - -- (void)unmarkText { - imeInputEventInProgress = false; - [[markedText mutableString] setString:@""]; - - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (wd.im_active) { - DS_OSX->im_text = String(); - DS_OSX->im_selection = Point2i(); - - OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE); - } -} - -- (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 { - ERR_FAIL_COND_V(!DS_OSX->windows.has(window_id), NSMakeRect(0, 0, 0, 0)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - const NSRect contentRect = [wd.window_view frame]; - const float scale = DS_OSX->screen_get_max_scale(); - NSRect pointInWindowRect = NSMakeRect(wd.im_position.x / scale, contentRect.size.height - (wd.im_position.y / scale) - 1, 0, 0); - NSPoint pointOnScreen = [wd.window_object convertRectToScreen:pointInWindowRect].origin; - - return NSMakeRect(pointOnScreen.x, pointOnScreen.y, 0, 0); -} - -- (void)cancelComposition { - [self unmarkText]; - NSTextInputContext *currentInputContext = [NSTextInputContext currentInputContext]; - [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 *ctrlChars = [NSCharacterSet controlCharacterSet]; - NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - if ([characters rangeOfCharacterFromSet:ctrlChars].length && [characters rangeOfCharacterFromSet:wsnlChars].length == 0) { - NSTextInputContext *currentInputContext = [NSTextInputContext currentInputContext]; - [currentInputContext discardMarkedText]; - [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; - - _push_to_key_event_buffer(ke); - } - [self cancelComposition]; -} - -- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { - return NSDragOperationCopy; -} - -- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { - return NSDragOperationCopy; -} - -- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { - ERR_FAIL_COND_V(!DS_OSX->windows.has(window_id), NO); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (!wd.drop_files_callback.is_null()) { - Vector<String> files; - NSPasteboard *pboard = [sender draggingPasteboard]; - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 - NSArray *items = pboard.pasteboardItems; - for (NSPasteboardItem *item in items) { - NSString *path = [item stringForType:NSPasteboardTypeFileURL]; - NSString *ns = [NSURL URLWithString:path].path; - char *utfs = strdup([ns UTF8String]); - String ret; - ret.parse_utf8(utfs); - free(utfs); - files.push_back(ret); - } -#else - NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; - for (NSString *ns in filenames) { - char *utfs = strdup([ns UTF8String]); - String ret; - ret.parse_utf8(utfs); - free(utfs); - files.push_back(ret); - } -#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; -} - -- (BOOL)isOpaque { - return YES; -} - -- (BOOL)canBecomeKeyView { - if (DS_OSX->windows.has(window_id)) { - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - if (wd.no_focus) { - return NO; - } - } - return YES; -} - -- (BOOL)acceptsFirstResponder { - return YES; -} - -- (void)cursorUpdate:(NSEvent *)event { - DisplayServer::CursorShape p_shape = DS_OSX->cursor_shape; - DS_OSX->cursor_shape = DisplayServer::CURSOR_MAX; - DS_OSX->cursor_set_shape(p_shape); -} - -static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, MouseButton index, MouseButton mask, bool pressed) { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (pressed) { - DS_OSX->last_button_state |= mask; - } else { - DS_OSX->last_button_state &= (MouseButton)~mask; - } - - Ref<InputEventMouseButton> mb; - mb.instantiate(); - mb->set_window_id(window_id); - const Vector2 pos = _get_mouse_pos(wd, [event locationInWindow]); - _get_key_modifier_state([event modifierFlags], mb); - mb->set_button_index(index); - mb->set_pressed(pressed); - mb->set_position(pos); - mb->set_global_position(pos); - mb->set_button_mask(DS_OSX->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 { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (([event modifierFlags] & NSEventModifierFlagControl)) { - wd.mouse_down_control = true; - _mouseDownEvent(window_id, event, MouseButton::RIGHT, MouseButton::MASK_RIGHT, true); - } else { - wd.mouse_down_control = false; - _mouseDownEvent(window_id, event, MouseButton::LEFT, MouseButton::MASK_LEFT, true); - } -} - -- (void)mouseDragged:(NSEvent *)event { - [self mouseMoved:event]; -} - -- (void)mouseUp:(NSEvent *)event { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (wd.mouse_down_control) { - _mouseDownEvent(window_id, event, MouseButton::RIGHT, MouseButton::MASK_RIGHT, false); - } else { - _mouseDownEvent(window_id, event, MouseButton::LEFT, MouseButton::MASK_LEFT, false); - } -} - -- (void)mouseMoved:(NSEvent *)event { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - NSPoint delta = NSMakePoint([event deltaX], [event deltaY]); - NSPoint mpos = [event locationInWindow]; - - if (DS_OSX->ignore_warp) { - // Discard late events, before warp - if (([event timestamp]) < DS_OSX->last_warp) { - return; - } - DS_OSX->ignore_warp = false; - return; - } - - if (DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED || DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED_HIDDEN) { - // Discard late events - if (([event timestamp]) < DS_OSX->last_warp) { - return; - } - - // Warp affects next event delta, subtract previous warp deltas - List<DisplayServerOSX::WarpEvent>::Element *F = DS_OSX->warp_events.front(); - while (F) { - if (F->get().timestamp < [event timestamp]) { - List<DisplayServerOSX::WarpEvent>::Element *E = F; - delta.x -= E->get().delta.x; - delta.y -= E->get().delta.y; - F = F->next(); - DS_OSX->warp_events.erase(E); - } else { - F = F->next(); - } - } - - // Confine mouse position to the window, and update delta - NSRect frame = [wd.window_object frame]; - NSPoint conf_pos = mpos; - conf_pos.x = CLAMP(conf_pos.x + delta.x, 0.f, frame.size.width); - conf_pos.y = CLAMP(conf_pos.y - delta.y, 0.f, frame.size.height); - delta.x = conf_pos.x - mpos.x; - delta.y = mpos.y - conf_pos.y; - mpos = conf_pos; - - // Move mouse cursor - NSRect pointInWindowRect = NSMakeRect(conf_pos.x, conf_pos.y, 0, 0); - conf_pos = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin; - conf_pos.y = CGDisplayBounds(CGMainDisplayID()).size.height - conf_pos.y; - CGWarpMouseCursorPosition(conf_pos); - - // Save warp data - DS_OSX->last_warp = [[NSProcessInfo processInfo] systemUptime]; - DisplayServerOSX::WarpEvent ev; - ev.timestamp = DS_OSX->last_warp; - ev.delta = delta; - DS_OSX->warp_events.push_back(ev); - } - - Ref<InputEventMouseMotion> mm; - mm.instantiate(); - - mm->set_window_id(window_id); - mm->set_button_mask(DS_OSX->last_button_state); - const Vector2i pos = _get_mouse_pos(wd, mpos); - mm->set_position(pos); - mm->set_pressure([event pressure]); - if ([event subtype] == NSEventSubtypeTabletPoint) { - const NSPoint p = [event tilt]; - mm->set_tilt(Vector2(p.x, p.y)); - } - mm->set_global_position(pos); - mm->set_speed(Input::get_singleton()->get_last_mouse_speed()); - const Vector2i relativeMotion = Vector2i(delta.x, delta.y) * DS_OSX->screen_get_max_scale(); - mm->set_relative(relativeMotion); - _get_key_modifier_state([event modifierFlags], mm); - - Input::get_singleton()->set_mouse_position(wd.mouse_pos); - Input::get_singleton()->parse_input_event(mm); -} - -- (void)rightMouseDown:(NSEvent *)event { - _mouseDownEvent(window_id, event, MouseButton::RIGHT, MouseButton::MASK_RIGHT, true); -} - -- (void)rightMouseDragged:(NSEvent *)event { - [self mouseMoved:event]; -} - -- (void)rightMouseUp:(NSEvent *)event { - _mouseDownEvent(window_id, event, MouseButton::RIGHT, MouseButton::MASK_RIGHT, false); -} - -- (void)otherMouseDown:(NSEvent *)event { - if ((int)[event buttonNumber] == 2) { - _mouseDownEvent(window_id, event, MouseButton::MIDDLE, MouseButton::MASK_MIDDLE, true); - } else if ((int)[event buttonNumber] == 3) { - _mouseDownEvent(window_id, event, MouseButton::MB_XBUTTON1, MouseButton::MASK_XBUTTON1, true); - } else if ((int)[event buttonNumber] == 4) { - _mouseDownEvent(window_id, event, MouseButton::MB_XBUTTON2, MouseButton::MASK_XBUTTON2, true); - } else { - return; - } -} - -- (void)otherMouseDragged:(NSEvent *)event { - [self mouseMoved:event]; -} - -- (void)otherMouseUp:(NSEvent *)event { - if ((int)[event buttonNumber] == 2) { - _mouseDownEvent(window_id, event, MouseButton::MIDDLE, MouseButton::MASK_MIDDLE, false); - } else if ((int)[event buttonNumber] == 3) { - _mouseDownEvent(window_id, event, MouseButton::MB_XBUTTON1, MouseButton::MASK_XBUTTON1, false); - } else if ((int)[event buttonNumber] == 4) { - _mouseDownEvent(window_id, event, MouseButton::MB_XBUTTON2, MouseButton::MASK_XBUTTON2, false); - } else { - return; - } -} - -- (void)mouseExited:(NSEvent *)event { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (DS_OSX->mouse_mode != DisplayServer::MOUSE_MODE_CAPTURED) { - DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_EXIT); - } -} - -- (void)mouseEntered:(NSEvent *)event { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - if (DS_OSX->mouse_mode != DisplayServer::MOUSE_MODE_CAPTURED) { - DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_ENTER); - } - - DisplayServer::CursorShape p_shape = DS_OSX->cursor_shape; - DS_OSX->cursor_shape = DisplayServer::CURSOR_MAX; - DS_OSX->cursor_set_shape(p_shape); -} - -- (void)magnifyWithEvent:(NSEvent *)event { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - Ref<InputEventMagnifyGesture> ev; - ev.instantiate(); - ev->set_window_id(window_id); - _get_key_modifier_state([event modifierFlags], ev); - ev->set_position(_get_mouse_pos(wd, [event locationInWindow])); - ev->set_factor([event magnification] + 1.0); - - Input::get_singleton()->parse_input_event(ev); -} - -- (void)viewDidChangeBackingProperties { - // nothing left to do here -} - -- (void)updateTrackingAreas { - if (trackingArea != nil) { - [self removeTrackingArea:trackingArea]; - [trackingArea release]; - } - - NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingCursorUpdate | NSTrackingInVisibleRect; - trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; - - [self addTrackingArea:trackingArea]; - [super updateTrackingAreas]; -} - -static bool isNumpadKey(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::UNKNOWN, /* 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::UNKNOWN, /* F18 */ - /* 50 */ Key::UNKNOWN, /* 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::UNKNOWN, /* 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 -static Key translateKey(unsigned int key) { - if (key >= 128) { - return Key::UNKNOWN; - } - - return _osx_to_godot_table[key]; -} - -// Translates a Godot keycode back to a OSX keycode -static unsigned int unmapKey(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 } -}; - -static Key remapKey(unsigned int key, unsigned int state) { - if (isNumpadKey(key)) { - return translateKey(key); - } - - TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); - if (!currentKeyboard) { - return translateKey(key); - } - - CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); - if (!layoutData) { - return translateKey(key); - } - - const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); - - UInt32 keysDown = 0; - UniChar chars[4]; - UniCharCount realLength; - - OSStatus err = UCKeyTranslate(keyboardLayout, - key, - kUCKeyActionDisplay, - (state >> 8) & 0xFF, - LMGetKbdType(), - kUCKeyTranslateNoDeadKeysBit, - &keysDown, - sizeof(chars) / sizeof(chars[0]), - &realLength, - chars); - - if (err != noErr) { - return translateKey(key); - } - - for (unsigned int i = 0; i < 55; i++) { - if (_keycodes[i].kchar == chars[0]) { - return _keycodes[i].kcode; - } - } - return translateKey(key); -} - -- (void)keyDown:(NSEvent *)event { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - ignore_momentum_scroll = true; - - // Ignore all input if IME input is in progress - if (!imeInputEventInProgress) { - NSString *characters = [event characters]; - NSUInteger length = [characters length]; - - if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([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 = remapKey([event keyCode], [event modifierFlags]); - ke.physical_keycode = translateKey([event keyCode]); - ke.raw = true; - ke.unicode = codepoint; - - _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 = remapKey([event keyCode], [event modifierFlags]); - ke.physical_keycode = translateKey([event keyCode]); - ke.raw = false; - ke.unicode = 0; - - _push_to_key_event_buffer(ke); - } - } - - // Pass events to IME handler - if (wd.im_active) { - [self interpretKeyEvents:[NSArray arrayWithObject:event]]; - } -} - -- (void)flagsChanged:(NSEvent *)event { - ignore_momentum_scroll = true; - - // Ignore all input if IME input is in progress - if (!imeInputEventInProgress) { - 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 = remapKey(key, mod); - ke.physical_keycode = translateKey(key); - ke.unicode = 0; - - _push_to_key_event_buffer(ke); - } -} - -- (void)keyUp:(NSEvent *)event { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - // Ignore all input if IME input is in progress - if (!imeInputEventInProgress) { - 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(remapKey([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 = remapKey([event keyCode], [event modifierFlags]); - ke.physical_keycode = translateKey([event keyCode]); - ke.raw = true; - ke.unicode = codepoint; - - _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 = remapKey([event keyCode], [event modifierFlags]); - ke.physical_keycode = translateKey([event keyCode]); - ke.raw = true; - ke.unicode = 0; - - _push_to_key_event_buffer(ke); - } - } -} - -inline void sendScrollEvent(DisplayServer::WindowID window_id, MouseButton button, double factor, int modifierFlags) { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - MouseButton mask = mouse_button_to_mask(button); - - Ref<InputEventMouseButton> sc; - sc.instantiate(); - - sc->set_window_id(window_id); - _get_key_modifier_state(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); - DS_OSX->last_button_state |= (MouseButton)mask; - sc->set_button_mask(DS_OSX->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); - DS_OSX->last_button_state &= (MouseButton)~mask; - sc->set_button_mask(DS_OSX->last_button_state); - - Input::get_singleton()->parse_input_event(sc); -} - -inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy, int modifierFlags) { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - Ref<InputEventPanGesture> pg; - pg.instantiate(); - - pg->set_window_id(window_id); - _get_key_modifier_state(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 { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - double deltaX, deltaY; - - _get_mouse_pos(wd, [event locationInWindow]); - - deltaX = [event scrollingDeltaX]; - deltaY = [event scrollingDeltaY]; - - if ([event hasPreciseScrollingDeltas]) { - deltaX *= 0.03; - deltaY *= 0.03; - } - - if ([event momentumPhase] != NSEventPhaseNone) { - if (ignore_momentum_scroll) { - return; - } - } else { - ignore_momentum_scroll = false; - } - - if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) { - sendPanEvent(window_id, deltaX, deltaY, [event modifierFlags]); - } else { - if (fabs(deltaX)) { - sendScrollEvent(window_id, 0 > deltaX ? MouseButton::WHEEL_RIGHT : MouseButton::WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]); - } - if (fabs(deltaY)) { - sendScrollEvent(window_id, 0 < deltaY ? MouseButton::WHEEL_UP : MouseButton::WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]); - } - } -} - -@end - -/*************************************************************************/ -/* GodotWindow */ -/*************************************************************************/ - -@interface GodotWindow : NSWindow { -} - -@end - -@implementation GodotWindow - -- (BOOL)canBecomeKeyWindow { - // Required for NSBorderlessWindowMask windows - for (Map<DisplayServer::WindowID, DisplayServerOSX::WindowData>::Element *E = DS_OSX->windows.front(); E; E = E->next()) { - if (E->get().window_object == self) { - if (E->get().no_focus) { - return NO; - } - } - } - return YES; -} - -- (BOOL)canBecomeMainWindow { - // Required for NSBorderlessWindowMask windows - for (Map<DisplayServer::WindowID, DisplayServerOSX::WindowData>::Element *E = DS_OSX->windows.front(); E; E = E->next()) { - if (E->get().window_object == self) { - if (E->get().no_focus) { - return NO; - } - } - } - return YES; -} - -@end - -/*************************************************************************/ -/* DisplayServerOSX */ -/*************************************************************************/ - -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_CONSOLE_WINDOW: - 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: - return true; - default: { - } - } - return false; -} - -String DisplayServerOSX::get_name() const { - return "OSX"; -} - -const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const { - const NSMenu *menu = nullptr; - if (p_menu_root == "") { - // Main menu.x - 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()]]; - 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; -} - -void DisplayServerOSX::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) { - _THREAD_SAFE_METHOD_ - - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""]; - GlobalMenuItem *obj = [[[GlobalMenuItem alloc] init] autorelease]; - obj->callback = p_callback; - obj->meta = p_tag; - obj->checkable = false; - [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) { - _THREAD_SAFE_METHOD_ - - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""]; - GlobalMenuItem *obj = [[[GlobalMenuItem alloc] init] autorelease]; - obj->callback = p_callback; - obj->meta = p_tag; - obj->checkable = true; - [menu_item setRepresentedObject:obj]; - } -} - -void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, 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; - } - NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@""]; - [menu setSubmenu:sub_menu forItem:menu_item]; - } -} - -void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root) { - _THREAD_SAFE_METHOD_ - - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - [menu addItem:[NSMenuItem separatorItem]]; - } -} - -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) { - GlobalMenuItem *obj = [menu_item representedObject]; - if (obj) { - return obj->checkable; - } - } - } - return false; -} - -Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_root, int p_idx) { - _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) { - GlobalMenuItem *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) { - _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) { - GlobalMenuItem *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) { - _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) { - char *utfs = strdup([[menu_item title] UTF8String]); - String ret; - ret.parse_utf8(utfs); - free(utfs); - return ret; - } - } - return String(); -} - -String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) { - _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 (Map<String, NSMenu *>::Element *E = submenu.front(); E; E = E->next()) { - if (E->get() == sub_menu) - return E->key(); - } - } - } - } - return String(); -} - -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) { - GlobalMenuItem *obj = [menu_item representedObject]; - obj->checkable = p_checkable; - } - } -} - -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) { - GlobalMenuItem *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) { - GlobalMenuItem *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]; - } - } -} - -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]; - } - } -} - -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); - } - - [window release]; - 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]; - - char *utfs = strdup([[input stringValue] UTF8String]); - String ret; - ret.parse_utf8(utfs); - free(utfs); - - 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); - } - - [window release]; - return OK; -} - -void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) { - _THREAD_SAFE_METHOD_ - - if (p_mode == mouse_mode) { - return; - } - - WindowData &wd = windows[MAIN_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) { - CursorShape p_shape = cursor_shape; - cursor_shape = DisplayServer::CURSOR_MAX; - cursor_set_shape(p_shape); - } -} - -DisplayServer::MouseMode DisplayServerOSX::mouse_get_mode() const { - return mouse_mode; -} - -void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) { - _THREAD_SAFE_METHOD_ - - if (mouse_mode == MOUSE_MODE_CAPTURED) { - last_mouse_pos = p_to; - } else { - WindowData &wd = windows[MAIN_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_to.x / scale, contentRect.size.height - (p_to.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 { - return last_mouse_pos; -} - -Point2i DisplayServerOSX::mouse_get_absolute_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)) { - return Vector2i((int)mouse_pos.x, (int)-mouse_pos.y) * scale + _get_screens_origin(); - } - } - return Vector2i(); -} - -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]; - - char *utfs = strdup([string UTF8String]); - String ret; - ret.parse_utf8(utfs); - free(utfs); - - return ret; -} - -int DisplayServerOSX::get_screen_count() const { - _THREAD_SAFE_METHOD_ - - NSArray *screenArray = [NSScreen screens]; - return [screenArray count]; -} - -// 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 - -static bool displays_arrangement_dirty = true; -static bool displays_scale_dirty = true; -static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) { - displays_arrangement_dirty = true; - displays_scale_dirty = true; -} - -Point2i DisplayServerOSX::_get_screens_origin() const { - static Point2i origin; - - if (displays_arrangement_dirty) { - 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; - } - - 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(); -} - -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_ - - static float scale = 1.f; - if (displays_scale_dirty) { - int screen_count = get_screen_count(); - for (int i = 0; i < screen_count; i++) { - scale = fmax(scale, screen_get_scale(i)); - } - displays_scale_dirty = false; - } - return 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(); -} - -Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const { - _THREAD_SAFE_METHOD_ - - Vector<int> ret; - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - 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]; - - if (wd.no_focus) { - [wd.window_object orderFront:nil]; - } else { - [wd.window_object makeKeyAndOrderFront:nil]; - } -} - -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); - } -} - -DisplayServerOSX::WindowID DisplayServerOSX::_find_window_id(id p_window) { - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - if (E->get().window_object == p_window) { - return E->key(); - } - } - return INVALID_WINDOW_ID; -} - -void DisplayServerOSX::_update_window(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 - [p_wd.window_object setLevel:NSMainMenuWindowLevel + 1]; - [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) { - [p_wd.window_object setLevel:NSFloatingWindowLevel]; - } else { - [p_wd.window_object setLevel:NSNormalWindowLevel]; - } - [p_wd.window_object setHidesOnDeactivate:NO]; - } -} - -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_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; -} - -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; -} - -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_ - 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); -} - -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_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_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove]; - } -} - -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]; - - NSRect nsrect = [wd.window_object frame]; - 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(); - - [wd.window_object setFrameTopLeftPoint:NSMakePoint(position.x, position.y)]; - - _update_window(wd); - _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); -} - -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(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(); -} - -bool DisplayServerOSX::window_is_maximize_allowed(WindowID p_window) const { - return true; -} - -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_OSX::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 = [wd.window_view layer]; - if (layer) { - [layer setOpaque:NO]; - } -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - //TODO - implement transparency for Vulkan - } -#endif -#if defined(GLES3_ENABLED) - if (rendering_driver == "opengl3") { - //TODO - reimplement OpenGLES - } -#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 = [wd.window_view layer]; - if (layer) { - [layer setOpaque:YES]; - } -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - //TODO - implement transparency for Vulkan - } -#endif -#if defined(GLES3_ENABLED) - if (rendering_driver == "opengl3") { - //TODO - reimplement OpenGLES - } -#endif - wd.layered_window = false; - } -#if defined(GLES3_ENABLED) - if (rendering_driver == "opengl3") { - //TODO - reimplement OpenGLES - } -#endif -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - //TODO - implement transparency for Vulkan - } -#endif - 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::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_FULLSCREEN: { - [wd.window_object setLevel:NSNormalWindowLevel]; - if (wd.layered_window) { - _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_FULLSCREEN: { - if (wd.layered_window) - _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; -} - -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 fs - 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 { - if (wd.layered_window) - _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(wd); - if ([wd.window_object isVisible]) { - if (wd.no_focus) { - [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) { - [wd.window_object setLevel:NSFloatingWindowLevel]; - } else { - [wd.window_object setLevel:NSNormalWindowLevel]; - } - } break; - case WINDOW_FLAG_TRANSPARENT: { - wd.layered_window = p_enabled; - 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; - 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 [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; - 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.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 (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - 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; -} - -bool DisplayServerOSX::get_swap_cancel_ok() { - return false; -} - -void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { - _THREAD_SAFE_METHOD_ - - ERR_FAIL_INDEX(p_shape, CURSOR_MAX); - - if (cursor_shape == p_shape) { - return; - } - - if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) { - cursor_shape = p_shape; - return; - } - - if (cursors[p_shape] != nullptr) { - [cursors[p_shape] set]; - } else { - switch (p_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: - [_cursorFromSelector(@selector(_windowResizeNorthSouthCursor), @selector(resizeUpDownCursor)) set]; - break; - case CURSOR_HSIZE: - [_cursorFromSelector(@selector(_windowResizeEastWestCursor), @selector(resizeLeftRightCursor)) set]; - break; - case CURSOR_BDIAGSIZE: - [_cursorFromSelector(@selector(_windowResizeNorthEastSouthWestCursor)) set]; - break; - case CURSOR_FDIAGSIZE: - [_cursorFromSelector(@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: - [_cursorFromSelector(@selector(_helpCursor)) set]; - break; - default: { - } - } - } - - cursor_shape = p_shape; -} - -DisplayServerOSX::CursorShape DisplayServerOSX::cursor_get_shape() const { - return cursor_shape; -} - -void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { - _THREAD_SAFE_METHOD_ - - if (p_cursor.is_valid()) { - Map<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape); - - if (cursor_c) { - if (cursor_c->get()[0] == p_cursor && cursor_c->get()[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] release]; - 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]; - } - } - - [imgrep release]; - [nsimage release]; - } else { - // Reset to default system cursor - if (cursors[p_shape] != nullptr) { - [cursors[p_shape] release]; - cursors[p_shape] = nullptr; - } - - CursorShape c = cursor_shape; - cursor_shape = CURSOR_MAX; - cursor_set_shape(c); - - cursors_cache.erase(p_shape); - } -} - -struct LayoutInfo { - String name; - String code; -}; - -static Vector<LayoutInfo> kbd_layouts; -static int current_layout = 0; -static bool keyboard_layout_dirty = true; -static void keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) { - kbd_layouts.clear(); - current_layout = 0; - keyboard_layout_dirty = true; -} - -void _update_keyboard_layouts() { - @autoreleasepool { - TISInputSourceRef cur_source = TISCopyCurrentKeyboardInputSource(); - NSString *cur_name = (NSString *)TISGetInputSourceProperty(cur_source, kTISPropertyLocalizedName); - CFRelease(cur_source); - - // Enum IME layouts - NSDictionary *filter_ime = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardInputMode }; - NSArray *list_ime = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_ime, false); - for (NSUInteger i = 0; i < [list_ime count]; i++) { - LayoutInfo ly; - NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyLocalizedName); - ly.name.parse_utf8([name UTF8String]); - - NSArray *langs = (NSArray *)TISGetInputSourceProperty((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; - } - } - [list_ime release]; - - // Enum plain keyboard layouts - NSDictionary *filter_kbd = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardLayout }; - NSArray *list_kbd = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_kbd, false); - for (NSUInteger i = 0; i < [list_kbd count]; i++) { - LayoutInfo ly; - NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyLocalizedName); - ly.name.parse_utf8([name UTF8String]); - - NSArray *langs = (NSArray *)TISGetInputSourceProperty((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; - } - } - [list_kbd release]; - } - - keyboard_layout_dirty = false; -} - -int DisplayServerOSX::keyboard_get_layout_count() const { - if (keyboard_layout_dirty) { - _update_keyboard_layouts(); - } - return kbd_layouts.size(); -} - -void DisplayServerOSX::keyboard_set_current_layout(int p_index) { - if (keyboard_layout_dirty) { - _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 = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_kbd, false); - for (NSUInteger i = 0; i < [list_kbd count]; i++) { - NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyLocalizedName); - if ([name isEqualToString:cur_name]) { - TISSelectInputSource((TISInputSourceRef)[list_kbd objectAtIndex:i]); - break; - } - } - [list_kbd release]; - - NSDictionary *filter_ime = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardInputMode }; - NSArray *list_ime = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_ime, false); - for (NSUInteger i = 0; i < [list_ime count]; i++) { - NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyLocalizedName); - if ([name isEqualToString:cur_name]) { - TISSelectInputSource((TISInputSourceRef)[list_ime objectAtIndex:i]); - break; - } - } - [list_ime release]; -} - -int DisplayServerOSX::keyboard_get_current_layout() const { - if (keyboard_layout_dirty) { - _update_keyboard_layouts(); - } - - return current_layout; -} - -String DisplayServerOSX::keyboard_get_layout_language(int p_index) const { - if (keyboard_layout_dirty) { - _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) { - _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 = unmapKey((Key)keycode_no_mod); - return (Key)(remapKey(osx_keycode, 0) | modifiers); -} - -void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) { - Ref<InputEvent> ev = p_event; - Input::get_singleton()->parse_input_event(ev); -} - -void DisplayServerOSX::_release_pressed_events() { - _THREAD_SAFE_METHOD_ - if (Input::get_singleton()) { - Input::get_singleton()->release_pressed_events(); - } -} - -NSMenu *DisplayServerOSX::_get_dock_menu() const { - return dock_menu; -} - -void DisplayServerOSX::_menu_callback(id p_sender) { - if (![p_sender representedObject]) { - return; - } - - GlobalMenuItem *value = [p_sender representedObject]; - - if (value) { - if (value->checkable) { - 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); - } - } -} - -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::_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::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 (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - WindowData &wd = E->get(); - if (wd.mpath.size() > 0) { - const Vector2 mpos = _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); - if (Geometry2D::is_point_in_polygon(mpos, 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]; - } - } - } - - [autoreleasePool drain]; - autoreleasePool = [[NSAutoreleasePool alloc] init]; -} - -void DisplayServerOSX::force_process_and_drop_events() { - _THREAD_SAFE_METHOD_ - - drop_events = true; - process_events(); - drop_events = false; -} - -void DisplayServerOSX::set_native_icon(const String &p_filename) { - _THREAD_SAFE_METHOD_ - - FileAccess *f = FileAccess::open(p_filename, FileAccess::READ); - ERR_FAIL_COND(!f); - - Vector<uint8_t> data; - uint64_t len = f->get_length(); - data.resize(len); - f->get_buffer((uint8_t *)&data.write[0], len); - memdelete(f); - - NSData *icon_data = [[[NSData alloc] initWithBytes:&data.write[0] length:len] autorelease]; - ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data."); - - NSImage *icon = [[[NSImage alloc] initWithData:icon_data] autorelease]; - 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]; - - [imgrep release]; - [nsimg release]; -} - -void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { - _THREAD_SAFE_METHOD_ -#if defined(GLES3_ENABLED) - if (rendering_driver == "opengl3") { - gl_manager->swap_buffers(); - } -#endif -#if defined(VULKAN_ENABLED) - if (rendering_driver == "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 (rendering_driver == "opengl3") { - return (gl_manager->is_using_vsync() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED); - } -#endif -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - return context_vulkan->get_vsync_mode(p_window); - } -#endif - return DisplayServer::VSYNC_ENABLED; -} - -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::gl_window_make_current(DisplayServer::WindowID p_window_id) { -#if defined(GLES3_ENABLED) - gl_manager->window_make_current(p_window_id); -#endif -} - -Point2i DisplayServerOSX::ime_get_selection() const { - return im_selection; -} - -String DisplayServerOSX::ime_get_text() const { - return im_text; -} - -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 (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - if ([E->get().window_object windowNumber] == wnum) { - return E->key(); - } - } - return INVALID_WINDOW_ID; -} - -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; -} - -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; -} - -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_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]; - - if ([wd.window_object respondsToSelector:@selector(setTabbingMode:)]) { - [wd.window_object setTabbingMode:NSWindowTabbingModeDisallowed]; - } - - CALayer *layer = [wd.window_view layer]; - if (layer) { - layer.contentsScale = scale; - } - -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - 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 (rendering_driver == "opengl3") { - 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 = [wd.window_view layer]; - if (layer) { - layer.contentsScale = scale; - } - -#if defined(GLES3_ENABLED) - if (rendering_driver == "opengl3") { - gl_manager->window_resize(id, wd.size.width, wd.size.height); - } -#endif -#if defined(VULKAN_ENABLED) - if (rendering_driver == "vulkan") { - context_vulkan->window_resize(id, wd.size.width, wd.size.height); - } -#endif - - return id; -} - -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; - - 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_null()) { - return; - } - callable.call((const Variant **)&evp, 1, ret, ce); - } - } else { - //send to all windows - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - Callable callable = E->get().input_event_callback; - if (callable.is_null()) { - continue; - } - callable.call((const Variant **)&evp, 1, ret, ce); - } - } - - in_dispatch_input_event = false; - } -} - -void DisplayServerOSX::release_rendering_thread() { -} - -void DisplayServerOSX::make_rendering_thread() { -} - -void DisplayServerOSX::swap_buffers() { -#if defined(GLES3_ENABLED) - gl_manager->swap_buffers(); -#endif -} - -void DisplayServerOSX::console_set_visible(bool p_enabled) { - //TODO - open terminal and redirect -} - -bool DisplayServerOSX::is_console_visible() const { - return isatty(STDIN_FILENO); -} - -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; - drop_events = false; - - memset(cursors, 0, sizeof(cursors)); - cursor_shape = CURSOR_ARROW; - - key_event_pos = 0; - mouse_mode = MOUSE_MODE_VISIBLE; - - autoreleasePool = [[NSAutoreleasePool alloc] init]; - - eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - ERR_FAIL_COND(!eventSource); - - CGEventSourceSetLocalEventsSuppressionInterval(eventSource, 0.0); - - keyboard_layout_dirty = true; - displays_arrangement_dirty = true; - displays_scale_dirty = true; - - // 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); - - 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"]; - - // Setup Apple menu - apple_menu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - title = [NSString stringWithFormat:NSLocalizedString(@"About %@", nil), nsappname]; - [apple_menu addItemWithTitle:title action:@selector(showAbout:) keyEquivalent:@""]; - - [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]; - [services release]; - - [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]; - - //!!!!!!!!!!!!!!!!!!!!!!!!!! - //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() { - if (dock_menu) { - [dock_menu release]; - } - - for (Map<String, NSMenu *>::Element *E = submenu.front(); E; E = E->next()) { - [E->get() release]; - } - - //destroy all windows - for (Map<WindowID, WindowData>::Element *E = windows.front(); E;) { - Map<WindowID, WindowData>::Element *F = E; - E = E->next(); - [F->get().window_object setContentView:nil]; - [F->get().window_object close]; - } - - //destroy drivers -#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(); -} - -void DisplayServerOSX::register_osx_driver() { - register_create_function("osx", create_func, get_rendering_drivers_func); -} diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp deleted file mode 100644 index 1164d76580..0000000000 --- a/platform/osx/export/export.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/*************************************************************************/ -/* export.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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() { - 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 f8cf41c0e7..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-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 8126510245..0000000000 --- a/platform/osx/export/export_plugin.cpp +++ /dev/null @@ -1,1141 +0,0 @@ -/*************************************************************************/ -/* export_plugin.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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" - -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"); -} - -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::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine")); - 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::BOOL, "display/high_res"), false)); - 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::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "")); - -#ifdef OSX_ENABLED - 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/hardened_runtime"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "")); - - if (!Engine::get_singleton()->has_singleton("GodotSharp")) { - // These entitlements are required to run managed code, and are always enabled in Mono builds. - 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"), "")); -#endif - - 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->create_from_image(copy); - String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png"); - ResourceSaver::save(path, it); - - FileAccess *f = FileAccess::open(path, FileAccess::READ); - if (!f) { - // Clean up generated file. - DirAccess::remove_file_or_error(path); - ERR_FAIL(); - } - - int ofs = data.size(); - uint64_t len = f->get_length(); - data.resize(data.size() + len + 8); - f->get_buffer(&data.write[ofs + 8], len); - memdelete(f); - 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", p_binary) + "\n"; - } else if (lines[i].find("$info") != -1) { - strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\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") ? "<true/>" : "<false/>") + "\n"; - } else if (lines[i].find("$camera_usage_description") != -1) { - String description = p_preset->get("privacy/camera_usage_description"); - strnew += lines[i].replace("$camera_usage_description", description) + "\n"; - } else if (lines[i].find("$microphone_usage_description") != -1) { - String description = p_preset->get("privacy/microphone_usage_description"); - strnew += lines[i].replace("$microphone_usage_description", description) + "\n"; - } 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); - ERR_FAIL_COND_V(err != OK, err); - - print_line("altool (" + p_path + "):\n" + str); - if (str.find("RequestUUID") == -1) { - EditorNode::add_io_error("altool: " + str); - return FAILED; - } else { - print_line("Note: The notarization process generally takes less than an hour. When the process is completed, you'll receive an email."); - print_line(" You can check progress manually by opening a Terminal and running the following command:"); - print_line(" \"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\""); - } - -#endif - - return OK; -} - -Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path) { -#ifdef OSX_ENABLED - List<String> args; - - if (p_preset->get("codesign/timestamp")) { - args.push_back("--timestamp"); - } - if (p_preset->get("codesign/hardened_runtime")) { - 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 (p_preset->get("codesign/identity") == "") { - 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); - ERR_FAIL_COND_V(err != OK, err); - - print_line("codesign (" + p_path + "):\n" + str); - if (str.find("no identity found") != -1) { - EditorNode::add_io_error("codesign: no identity found"); - return FAILED; - } - if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) { - EditorNode::add_io_error("codesign: invalid entitlements file"); - return FAILED; - } -#endif - - return OK; -} - -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); - ERR_FAIL_COND_V(err != OK, err); - - print_line("hdiutil returned: " + str); - if (str.find("create failed") != -1) { - if (str.find("File exists") != -1) { - EditorNode::add_io_error("hdiutil: create failed - file exists"); - } else { - EditorNode::add_io_error("hdiutil: create failed"); - } - return FAILED; - } - - 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()) { - EditorNode::add_io_error(err); - return ERR_FILE_NOT_FOUND; - } - } - - if (!DirAccess::exists(p_path.get_base_dir())) { - return ERR_FILE_BAD_PATH; - } - - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - - if (ep.step("Creating app", 0)) { - return ERR_SKIP; - } - - unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); - if (!src_pkg_zip) { - EditorNode::add_io_error("Could not find template app to export:\n" + 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 (p_preset->get("application/name") != "") { - pkg_name = p_preset->get("application/name"); // app_name - } else 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 = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip"; - - // Create our application bundle. - String tmp_app_dir_name = pkg_name + ".app"; - String tmp_app_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name); - print_line("Exporting to " + tmp_app_path_name); - - Error err = OK; - - DirAccessRef tmp_app_dir = DirAccess::create_for_path(tmp_app_path_name); - if (!tmp_app_dir) { - err = ERR_CANT_CREATE; - } - - Array helpers = p_preset->get("codesign/entitlements/app_sandbox/helper_executables"); - - // Create our folder structure. - if (err == OK) { - print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); - err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS"); - } - - if (err == OK) { - print_line("Creating " + tmp_app_path_name + "/Contents/Frameworks"); - err = tmp_app_dir->make_dir_recursive(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) { - print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); - err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); - } - - // 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); - - String file = 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 (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") { - FileAccess *icon = FileAccess::open(iconpath, FileAccess::READ); - if (icon) { - data.resize(icon->get_length()); - icon->get_buffer(&data.write[0], icon->get_length()); - icon->close(); - memdelete(icon); - } - } 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_line("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) { - FileAccess *f = FileAccess::open(file, FileAccess::WRITE); - if (f) { - f->store_buffer(data.ptr(), data.size()); - f->close(); - if (is_execute) { - // chmod with 0755 if the file is executable. - FileAccess::set_unix_permissions(file, 0755); - } - memdelete(f); - } else { - err = ERR_CANT_CREATE; - } - } - } - - ret = unzGoToNextFile(src_pkg_zip); - } - - // We're done with our source zip. - unzClose(src_pkg_zip); - - if (!found_binary) { - ERR_PRINT("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); - err = ERR_FILE_NOT_FOUND; - } - - if (err == OK) { - if (ep.step("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, 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"); - - FileAccess *ent_f = FileAccess::open(ent_path, FileAccess::WRITE); - if (ent_f) { - 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>"); - - ent_f->close(); - memdelete(ent_f); - } else { - err = ERR_CANT_CREATE; - } - - if ((err == OK) && helpers.size() > 0) { - ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE); - if (ent_f) { - 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>"); - - ent_f->close(); - memdelete(ent_f); - } else { - err = ERR_CANT_CREATE; - } - } - } - - if ((err == OK) && helpers.size() > 0) { - DirAccessRef 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); - } - FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755); - } - } - - if (err == OK) { - DirAccessRef 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 (da->dir_exists(src_path)) { -#ifndef UNIX_ENABLED - WARN_PRINT("Relative symlinks are not supported, exported " + src_path.get_file() + " might be broken!"); -#endif - print_verbose("export framework: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file()); - err = da->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file()); - if (err == OK) { - err = da->copy_dir(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), -1, true); - } - } else { - print_verbose("export dylib: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file()); - err = da->copy(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file()); - } - if (err == OK && sign_enabled) { - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path); - } - } - } - - 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); - } - } - } - - if (err == OK && sign_enabled) { - if (ep.step("Code signing bundle", 2)) { - return ERR_SKIP; - } - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name, ent_path); - } - - if (export_format == "dmg") { - // Create a DMG. - if (err == OK) { - if (ep.step("Making DMG", 3)) { - return ERR_SKIP; - } - err = _create_dmg(p_path, pkg_name, tmp_app_path_name); - } - // Sign DMG. - if (err == OK && sign_enabled) { - if (ep.step("Code signing DMG", 3)) { - return ERR_SKIP; - } - err = _code_sign(p_preset, p_path, ent_path); - } - } else { - // Create ZIP. - if (err == OK) { - if (ep.step("Making ZIP", 3)) { - return ERR_SKIP; - } - if (FileAccess::exists(p_path)) { - OS::get_singleton()->move_to_trash(p_path); - } - - FileAccess *dst_f = nullptr; - zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f); - zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst); - - _zip_folder_recursive(zip, EditorPaths::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name); - - zipClose(zip, nullptr); - } - } - - bool noto_enabled = p_preset->get("notarization/enable"); - if (err == OK && noto_enabled) { - if (ep.step("Sending archive for notarization", 4)) { - return ERR_SKIP; - } - err = _notarize(p_preset, p_path); - } - - // Clean up temporary entitlements files. - DirAccess::remove_file_or_error(hlp_ent_path); - - // Clean up temporary .app dir. - tmp_app_dir->change_dir(tmp_app_path_name); - tmp_app_dir->erase_contents_recursive(); - tmp_app_dir->change_dir(".."); - tmp_app_dir->remove(tmp_app_dir_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_root_path.plus_file(p_folder); - - DirAccessRef 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"); - - 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); - - FileAccessRef fa = FileAccess::open(dir.plus_file(f), FileAccess::READ); - if (!fa) { - ERR_FAIL_MSG("Can't open file to read from path '" + String(dir.plus_file(f)) + "'."); - } - 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 (first official, and if defined custom templates). - - bool dvalid = exists_export_template("osx.zip", &err); - bool rvalid = dvalid; // Both in the same ZIP. - - 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"; - } - } - - 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"); - bool noto_enabled = p_preset->get("notarization/enable"); - if (noto_enabled) { - if (!sign_enabled) { - err += TTR("Notarization: code signing required.") + "\n"; - valid = false; - } - bool hr_enabled = p_preset->get("codesign/hardened_runtime"); - if (!hr_enabled) { - err += TTR("Notarization: hardened runtime required.") + "\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; - } - } - - if (!err.is_empty()) { - r_error = err; - } - return valid; -} - -EditorExportPlatformOSX::EditorExportPlatformOSX() { - Ref<Image> img = memnew(Image(_osx_logo)); - logo.instantiate(); - logo->create_from_image(img); -} - -EditorExportPlatformOSX::~EditorExportPlatformOSX() { -} diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h deleted file mode 100644 index ca5086622e..0000000000 --- a/platform/osx/export/export_plugin.h +++ /dev/null @@ -1,128 +0,0 @@ -/*************************************************************************/ -/* export_plugin.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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_node.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); - 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); - -#ifdef OSX_ENABLED - bool use_codesign() const { return true; } - bool use_dmg() const { return true; } -#else - bool use_codesign() const { return false; } - 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 (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) { - if (r_error) { - *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c)); - } - 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; - -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"); - 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, Set<String> &p_features) override { - } - - EditorExportPlatformOSX(); - ~EditorExportPlatformOSX(); -}; - -#endif diff --git a/platform/osx/gl_manager_osx.h b/platform/osx/gl_manager_osx.h deleted file mode 100644 index f86bc805c1..0000000000 --- a/platform/osx/gl_manager_osx.h +++ /dev/null @@ -1,106 +0,0 @@ -/*************************************************************************/ -/* gl_manager_osx.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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_H -#define GL_MANAGER_OSX_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" - -#include <AppKit/AppKit.h> -#include <ApplicationServices/ApplicationServices.h> -#include <CoreVideo/CoreVideo.h> - -class GLManager_OSX { -public: - enum ContextType { - GLES_3_0_COMPATIBLE, - }; - -private: - struct GLWindow { - GLWindow() { in_use = false; } - bool in_use; - - DisplayServer::WindowID window_id; - int width; - int height; - - id window_view; - NSOpenGLContext *context; - }; - - LocalVector<GLWindow> _windows; - - NSOpenGLContext *_shared_context = nullptr; - GLWindow *_current_window; - - Error _create_context(GLWindow &win); - void _internal_set_current_window(GLWindow *p_win); - - GLWindow &get_window(unsigned int id) { return _windows[id]; } - const GLWindow &get_window(unsigned int id) const { return _windows[id]; } - - bool use_vsync; - 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); - - // get directly from the cached GLWindow - 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); - - Error initialize(); - - void set_use_vsync(bool p_use); - bool is_using_vsync() const; - - GLManager_OSX(ContextType p_context_type); - ~GLManager_OSX(); -}; - -#endif // defined(OSX_ENABLED) && defined(GLES3_ENABLED) - -#endif // GL_MANAGER_OSX_H diff --git a/platform/osx/gl_manager_osx.mm b/platform/osx/gl_manager_osx.mm deleted file mode 100644 index 60e0706fc0..0000000000 --- a/platform/osx/gl_manager_osx.mm +++ /dev/null @@ -1,233 +0,0 @@ -/*************************************************************************/ -/* gl_manager_osx.mm */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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.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) { - if (p_window_id >= (int)_windows.size()) { - _windows.resize(p_window_id + 1); - } - - GLWindow &win = _windows[p_window_id]; - win.in_use = true; - win.window_id = p_window_id; - win.width = p_width; - win.height = p_height; - win.window_view = p_view; - - if (_create_context(win) != OK) { - _windows.remove_at(_windows.size() - 1); - return FAILED; - } - - window_make_current(_windows.size() - 1); - - return OK; -} - -void GLManager_OSX::_internal_set_current_window(GLWindow *p_win) { - _current_window = p_win; -} - -void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { - if (p_window_id == -1) { - return; - } - - GLWindow &win = _windows[p_window_id]; - if (!win.in_use) { - return; - } - - 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) { - return get_window(p_window_id).width; -} - -int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) { - return get_window(p_window_id).height; -} - -void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) { - GLWindow &win = get_window(p_window_id); - win.in_use = false; - - if (_current_window == &win) { - _current_window = nullptr; - } -} - -void GLManager_OSX::release_current() { - if (!_current_window) { - return; - } - - [NSOpenGLContext clearCurrentContext]; -} - -void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) { - if (p_window_id == -1) { - return; - } - - GLWindow &win = _windows[p_window_id]; - if (!win.in_use) { - return; - } - - if (&win == _current_window) { - return; - } - - [win.context makeCurrentContext]; - - _internal_set_current_window(&win); -} - -void GLManager_OSX::make_current() { - if (!_current_window) { - return; - } - if (!_current_window->in_use) { - WARN_PRINT("current window not in use!"); - return; - } - [_current_window->context makeCurrentContext]; -} - -void GLManager_OSX::swap_buffers() { - // NO NEED TO CALL SWAP BUFFERS for each window... - // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml - - if (!_current_window) { - return; - } - if (!_current_window->in_use) { - WARN_PRINT("current window not in use!"); - return; - } - [_current_window->context flushBuffer]; -} - -void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) { - if (p_window_id == -1) { - return; - } - - GLWindow &win = _windows[p_window_id]; - if (!win.in_use) { - return; - } - - if (&win == _current_window) { - return; - } - - [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; - use_vsync = false; - _current_window = nullptr; -} - -GLManager_OSX::~GLManager_OSX() { - release_current(); -} - -#endif // GLES3_ENABLED -#endif // OSX diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm deleted file mode 100644 index 7e7dbf6afb..0000000000 --- a/platform/osx/godot_main_osx.mm +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************/ -/* godot_main_osx.mm */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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> - -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 - - 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 - - if (os.open_with_filename != "") { - char *argv_c = (char *)malloc(os.open_with_filename.utf8().size()); - memcpy(argv_c, os.open_with_filename.utf8().get_data(), os.open_with_filename.utf8().size()); - err = Main::setup(argv[0], 1, &argv_c); - free(argv_c); - } else { - err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]); - } - - 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/joypad_osx.cpp b/platform/osx/joypad_osx.cpp deleted file mode 100644 index 48d165d30b..0000000000 --- a/platform/osx/joypad_osx.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/*************************************************************************/ -/* joypad_osx.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 = (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 const Input::JoyAxisValue axis_correct(int p_value, int p_min, int p_max) { - Input::JoyAxisValue jx; - if (p_min < 0) { - jx.min = -1; - if (p_value < 0) { - jx.value = (float)-p_value / p_min; - } else - jx.value = (float)p_value / p_max; - } - if (p_min == 0) { - jx.min = 0; - jx.value = 0.0f + (float)p_value / p_max; - } - return jx; -} - -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); - const void *keys[2] = { (void *)CFSTR(kIOHIDDeviceUsagePageKey), (void *)CFSTR(kIOHIDDeviceUsageKey) }; - const void *vals[2] = { (void *)pageNumRef, (void *)usageNumRef }; - - if (pageNumRef && 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 2ba7f0d950..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-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 -#include <IOKit/hidsystem/IOHIDUsageTables.h> -#else -#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h> -#endif -#include <ForceFeedback/ForceFeedback.h> -#include <ForceFeedback/ForceFeedbackConstants.h> -#include <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; - 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/logo.png b/platform/osx/logo.png Binary files differdeleted file mode 100644 index b5a660b165..0000000000 --- a/platform/osx/logo.png +++ /dev/null diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h deleted file mode 100644 index 7e02f4e154..0000000000 --- a/platform/osx/os_osx.h +++ /dev/null @@ -1,114 +0,0 @@ -/*************************************************************************/ -/* os_osx.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 { - virtual void delete_main_loop() override; - - bool force_quit; - - JoypadOSX *joypad_osx = nullptr; - -#ifdef COREAUDIO_ENABLED - AudioDriverCoreAudio audio_driver; -#endif -#ifdef COREMIDI_ENABLED - MIDIDriverCoreMidi midi_driver; -#endif - - CrashHandler crash_handler; - - MainLoop *main_loop; - - static void pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context); - -public: - String open_with_filename; - -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; - -public: - 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) 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; - - Error shell_open(String p_uri) override; - - 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) override; - virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; - - virtual String get_unique_id() const override; //++ - - virtual bool _check_internal_feature_support(const String &p_feature) override; - - void run(); - - virtual void disable_crash_handler() override; - virtual bool is_disable_crash_handler() const override; - - virtual Error move_to_trash(const String &p_path) override; - - OS_OSX(); -}; - -#endif diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm deleted file mode 100644 index 39608bdea8..0000000000 --- a/platform/osx/os_osx.mm +++ /dev/null @@ -1,672 +0,0 @@ -/*************************************************************************/ -/* os_osx.mm */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 "dir_access_osx.h" -#include "display_server_osx.h" -#include "main/main.h" - -#include <dlfcn.h> -#include <libproc.h> -#include <mach-o/dyld.h> -#include <os/log.h> - -#define DS_OSX ((DisplayServerOSX *)(DisplayServerOSX::get_singleton())) - -/*************************************************************************/ -/* GodotApplication */ -/*************************************************************************/ - -@interface GodotApplication : NSApplication -@end - -@implementation GodotApplication - -- (void)sendEvent:(NSEvent *)event { - if (DS_OSX) { - DS_OSX->_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 - -/*************************************************************************/ -/* GodotApplicationDelegate */ -/*************************************************************************/ - -@interface GodotApplicationDelegate : NSObject -- (void)forceUnbundledWindowActivationHackStep1; -- (void)forceUnbundledWindowActivationHackStep2; -- (void)forceUnbundledWindowActivationHackStep3; -@end - -@implementation GodotApplicationDelegate - -- (void)forceUnbundledWindowActivationHackStep1 { - // Step1: Switch focus to macOS Dock. - // Required to perform step 2, TransformProcessType will fail if app is already the in focus. - for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) { - [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) { - // If executable is not a 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]; - } -} - -- (void)applicationDidResignActive:(NSNotification *)notification { - 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 { - if (DS_OSX) { - return DS_OSX->_menu_callback(sender); - } -} - -- (NSMenu *)applicationDockMenu:(NSApplication *)sender { - if (DS_OSX) { - return DS_OSX->_get_dock_menu(); - } else { - return nullptr; - } -} - -- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename { - // Note: may be called called before main loop init! - char *utfs = strdup([filename UTF8String]); - ((OS_OSX *)OS_OSX::get_singleton())->open_with_filename.parse_utf8(utfs); - free(utfs); - -#ifdef TOOLS_ENABLED - // Open new instance - if (OS_OSX::get_singleton()->get_main_loop()) { - List<String> args; - args.push_back(((OS_OSX *)OS_OSX::get_singleton())->open_with_filename); - String exec = OS_OSX::get_singleton()->get_executable_path(); - OS_OSX::get_singleton()->create_process(exec, args); - } -#endif - return YES; -} - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - if (DS_OSX) { - DS_OSX->_send_window_event(DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); - } - return NSTerminateCancel; -} - -- (void)showAbout:(id)sender { - if (OS_OSX::get_singleton()->get_main_loop()) { - OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT); - } -} - -@end - -/*************************************************************************/ -/* OSXTerminalLogger */ -/*************************************************************************/ - -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) { - 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; - } - } -}; - -/*************************************************************************/ -/* OS_OSX */ -/*************************************************************************/ - -String OS_OSX::get_unique_id() const { - static String serial_number; - - if (serial_number.is_empty()) { - io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); - CFStringRef serialNumberAsCFString = nullptr; - if (platformExpert) { - serialNumberAsCFString = (CFStringRef)IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0); - IOObjectRelease(platformExpert); - } - - NSString *serialNumberAsNSString = nil; - if (serialNumberAsCFString) { - serialNumberAsNSString = [NSString stringWithString:(NSString *)serialNumberAsCFString]; - CFRelease(serialNumberAsCFString); - } - - serial_number = [serialNumberAsNSString UTF8String]; - } - - return serial_number; -} - -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]; - [window release]; - if (key_window) { - [key_window makeKeyAndOrderFront:nil]; - } -} - -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::initialize_joypads() { - joypad_osx = memnew(JoypadOSX(Input::get_singleton())); -} - -void OS_OSX::initialize() { - crash_handler.initialize(); - - initialize_core(); - //ensure_user_data_dir(); -} - -void OS_OSX::finalize() { -#ifdef COREMIDI_ENABLED - midi_driver.close(); -#endif - - delete_main_loop(); - - if (joypad_osx) { - memdelete(joypad_osx); - } -} - -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; -} - -String OS_OSX::get_name() const { - return "macOS"; -} - -_FORCE_INLINE_ String _get_framework_executable(const String p_path) { - // Append framework executable name, or return as is if p_path is not a framework. - DirAccessRef 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; - } -} - -Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { - String path = _get_framework_executable(p_path); - - if (!FileAccess::exists(path)) { - // This code exists so gdnative can load .dylib files 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)) { - // This code exists so gdnative can load .dylib files 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() + "."); - 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 *resourcePath = [main resourcePath]; - ret.parse_utf8([resourcePath UTF8String]); - } - return ret; -} - -String OS_OSX::get_bundle_icon_path() const { - String ret; - - NSBundle *main = [NSBundle mainBundle]; - if (main) { - NSString *iconPath = [[main infoDictionary] objectForKey:@"CFBundleIconFile"]; - if (iconPath) { - ret.parse_utf8([iconPath 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) { - char *utfs = strdup([[paths firstObject] UTF8String]); - ret.parse_utf8(utfs); - free(utfs); - } - } - - 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 { - int ret; - pid_t pid; - char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; - - pid = getpid(); - 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_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); - } else { - return create_process(get_executable_path(), p_arguments, r_child_id); - } -} - -Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { - if (@available(macOS 10.15, *)) { - // 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 List<String>::Element *E = p_arguments.front(); E; E = E->next()) { - [arguments addObject:[NSString stringWithUTF8String:E->get().utf8().get_data()]]; - } - 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. - dispatch_release(lock); - - if (err == OK) { - if (r_child_id) { - *r_child_id = (ProcessID)pid; - } - } - - return err; - } else { - return OS_Unix::create_process(p_path, p_arguments, r_child_id); - } - } else { - return OS_Unix::create_process(p_path, p_arguments, r_child_id); - } -} - -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. - - if (get_singleton()->get_main_loop()) { - Main::force_redraw(); - if (!Main::is_iterating()) { // Avoid cyclic loop. - Main::iteration(); - } - } - - CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Prevent main loop from sleeping. -} - -void OS_OSX::run() { - force_quit = false; - - if (!main_loop) { - return; - } - - main_loop->initialize(); - - CFRunLoopObserverRef pre_wait_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, &pre_wait_observer_cb, nullptr); - CFRunLoopAddObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); - - 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([exception reason].UTF8String)); - } - }; - - CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); - CFRelease(pre_wait_observer); - - main_loop->finalize(); -} - -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(err.localizedDescription.UTF8String)); - return FAILED; - } - - return OK; -} - -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:@""] autorelease]; - [NSApp setMainMenu:main_menu]; - [NSApp finishLaunching]; - - id delegate = [[GodotApplicationDelegate alloc] init]; - ERR_FAIL_COND(!delegate); - [NSApp setDelegate:delegate]; - - //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]; -} - -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(); -} diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h deleted file mode 100644 index 7bfa466b97..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-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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/vulkan_context_osx.h b/platform/osx/vulkan_context_osx.h deleted file mode 100644 index 22d43688a3..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-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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" -#include <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 36c02c2497..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-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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 = 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() { -} |