diff options
Diffstat (limited to 'platform/osx')
-rw-r--r-- | platform/osx/context_gl_osx.h | 1 | ||||
-rw-r--r-- | platform/osx/context_gl_osx.mm | 11 | ||||
-rw-r--r-- | platform/osx/crash_handler_osx.h | 1 | ||||
-rw-r--r-- | platform/osx/detect.py | 35 | ||||
-rw-r--r-- | platform/osx/dir_access_osx.mm | 1 | ||||
-rw-r--r-- | platform/osx/display_server_osx.h | 196 | ||||
-rw-r--r-- | platform/osx/display_server_osx.mm | 938 | ||||
-rw-r--r-- | platform/osx/export/export.cpp | 508 | ||||
-rw-r--r-- | platform/osx/godot_main_osx.mm | 6 | ||||
-rw-r--r-- | platform/osx/joypad_osx.cpp | 53 | ||||
-rw-r--r-- | platform/osx/joypad_osx.h | 7 | ||||
-rw-r--r-- | platform/osx/logo.png | bin | 1751 -> 7195 bytes | |||
-rw-r--r-- | platform/osx/os_osx.h | 2 | ||||
-rw-r--r-- | platform/osx/os_osx.mm | 47 | ||||
-rw-r--r-- | platform/osx/platform_config.h | 1 | ||||
-rw-r--r-- | platform/osx/vulkan_context_osx.h | 1 | ||||
-rw-r--r-- | platform/osx/vulkan_context_osx.mm | 1 |
17 files changed, 1070 insertions, 739 deletions
diff --git a/platform/osx/context_gl_osx.h b/platform/osx/context_gl_osx.h index 7e436c5e36..cce00fb35f 100644 --- a/platform/osx/context_gl_osx.h +++ b/platform/osx/context_gl_osx.h @@ -41,7 +41,6 @@ #include <CoreVideo/CoreVideo.h> class ContextGL_OSX { - bool opengl_3_context; bool use_vsync; diff --git a/platform/osx/context_gl_osx.mm b/platform/osx/context_gl_osx.mm index 91d1332d24..2319e9eb1f 100644 --- a/platform/osx/context_gl_osx.mm +++ b/platform/osx/context_gl_osx.mm @@ -33,42 +33,34 @@ #if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) void ContextGL_OSX::release_current() { - [NSOpenGLContext clearCurrentContext]; } void ContextGL_OSX::make_current() { - [context makeCurrentContext]; } void ContextGL_OSX::update() { - [context update]; } void ContextGL_OSX::set_opacity(GLint p_opacity) { - [context setValues:&p_opacity forParameter:NSOpenGLCPSurfaceOpacity]; } int ContextGL_OSX::get_window_width() { - return OS::get_singleton()->get_video_mode().width; } int ContextGL_OSX::get_window_height() { - return OS::get_singleton()->get_video_mode().height; } void ContextGL_OSX::swap_buffers() { - [context flushBuffer]; } void ContextGL_OSX::set_use_vsync(bool p_use) { - CGLContextObj ctx = CGLGetCurrentContext(); if (ctx) { GLint swapInterval = p_use ? 1 : 0; @@ -78,12 +70,10 @@ void ContextGL_OSX::set_use_vsync(bool p_use) { } bool ContextGL_OSX::is_using_vsync() const { - return use_vsync; } Error ContextGL_OSX::initialize() { - framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); ERR_FAIL_COND_V(!framework, ERR_CANT_CREATE); @@ -161,7 +151,6 @@ Error ContextGL_OSX::initialize() { } ContextGL_OSX::ContextGL_OSX(id p_view, bool p_opengl_3_context) { - opengl_3_context = p_opengl_3_context; window_view = p_view; use_vsync = false; diff --git a/platform/osx/crash_handler_osx.h b/platform/osx/crash_handler_osx.h index abd9812596..9970f6045a 100644 --- a/platform/osx/crash_handler_osx.h +++ b/platform/osx/crash_handler_osx.h @@ -32,7 +32,6 @@ #define CRASH_HANDLER_OSX_H class CrashHandler { - bool disabled; public: diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 29aa8ece19..272ae1b620 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -24,11 +24,12 @@ def get_opts(): from SCons.Variables import BoolVariable, EnumVariable return [ - ("osxcross_sdk", "OSXCross SDK version", "darwin14"), + ("osxcross_sdk", "OSXCross SDK version", "darwin16"), ("MACOS_SDK_PATH", "Path to the macOS SDK", ""), BoolVariable( "use_static_mvk", - "Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables validation layers)", + "Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables" + " validation layers)", False, ), EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")), @@ -50,9 +51,11 @@ def configure(env): if env["target"] == "release": if env["optimize"] == "speed": # optimize for speed (default) - env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize", "-msse2"]) + env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"]) else: # optimize for size - env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize", "-msse2"]) + env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"]) + if env["arch"] != "arm64": + env.Prepend(CCFLAGS=["-msse2"]) if env["debug_symbols"] == "yes": env.Prepend(CCFLAGS=["-g1"]) @@ -72,7 +75,7 @@ def configure(env): elif env["target"] == "debug": env.Prepend(CCFLAGS=["-g3"]) - env.Prepend(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"]) + env.Prepend(CPPDEFINES=["DEBUG_ENABLED"]) ## Architecture @@ -86,9 +89,16 @@ def configure(env): 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", "-target", "arm64-apple-macos10.15"]) + env.Append(LINKFLAGS=["-arch", "arm64", "-mmacosx-version-min=10.15", "-target", "arm64-apple-macos10.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 - env.Append(CCFLAGS=["-arch", "x86_64"]) - env.Append(LINKFLAGS=["-arch", "x86_64"]) if env["macports_clang"] != "no": mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") mpclangver = env["macports_clang"] @@ -109,7 +119,10 @@ def configure(env): else: # osxcross build root = os.environ.get("OSXCROSS_ROOT", 0) - basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-" + 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: @@ -148,7 +161,8 @@ def configure(env): ## Dependencies if env["builtin_libtheora"]: - env["x86_libtheora_opt_gcc"] = True + if env["arch"] != "arm64": + env["x86_libtheora_opt_gcc"] = True ## Flags @@ -189,6 +203,3 @@ def configure(env): env.Append(LIBS=["vulkan"]) # env.Append(CPPDEFINES=['GLES_ENABLED', 'OPENGL_ENABLED']) - - env.Append(CCFLAGS=["-mmacosx-version-min=10.12"]) - env.Append(LINKFLAGS=["-mmacosx-version-min=10.12"]) diff --git a/platform/osx/dir_access_osx.mm b/platform/osx/dir_access_osx.mm index 66ea380903..7791ba5407 100644 --- a/platform/osx/dir_access_osx.mm +++ b/platform/osx/dir_access_osx.mm @@ -38,7 +38,6 @@ #include <Foundation/Foundation.h> String DirAccessOSX::fix_unicode_name(const char *p_name) const { - String fname; NSString *nsstr = [[NSString stringWithUTF8String:p_name] precomposedStringWithCanonicalMapping]; diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index 86ceb51763..d8f3f81ff6 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -33,7 +33,7 @@ #define BitMap _QDBitMap // Suppress deprecated QuickDraw definition. -#include "core/input/input_filter.h" +#include "core/input/input.h" #include "servers/display_server.h" #if defined(OPENGL_ENABLED) @@ -86,6 +86,14 @@ public: uint32_t unicode; }; + struct WarpEvent { + NSTimeInterval timestamp; + NSPoint delta; + }; + + List<WarpEvent> warp_events; + NSTimeInterval last_warp = 0; + Vector<KeyEvent> key_event_buffer; int key_event_pos; @@ -124,6 +132,7 @@ public: bool on_top = false; bool borderless = false; bool resize_disabled = false; + bool no_focus = false; }; Point2i im_selection; @@ -142,7 +151,6 @@ public: void _set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window); - float _display_scale(id screen) const; Point2i _get_screens_origin() const; Point2i _get_native_screen_position(int p_screen) const; @@ -169,132 +177,138 @@ public: bool in_dispatch_input_event = false; public: - virtual bool has_feature(Feature p_feature) const; - virtual String get_name() const; + 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()); - 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()); - virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu); - virtual void global_menu_add_separator(const String &p_menu_root); + 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; - virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const; - virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx); - virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx); - virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx); - virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx); + 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); - virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable); - virtual void global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback); - virtual void global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag); - virtual void global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text); - virtual void global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu); + 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; + 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); - virtual void global_menu_clear(const String &p_menu_root); + 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 void alert(const String &p_alert, const String &p_title = "ALERT!"); - virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback); - virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback); + virtual void alert(const String &p_alert, const String &p_title = "ALERT!") 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); - virtual MouseMode mouse_get_mode() const; + 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); - virtual Point2i mouse_get_position() const; - virtual Point2i mouse_get_absolute_position() const; - virtual int mouse_get_button_state() const; + 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 int mouse_get_button_state() const override; - virtual void clipboard_set(const String &p_text); - virtual String clipboard_get() const; + virtual void clipboard_set(const String &p_text) override; + virtual String clipboard_get() const override; - virtual int get_screen_count() const; - virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const; + 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; + virtual Vector<int> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i & = Rect2i()); - virtual void delete_sub_window(WindowID p_id); + virtual WindowID create_sub_window(WindowMode p_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); - virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); + 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); + virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override; - virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const; - virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID); + 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; - virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID); + 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); + 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); - virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const; + 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); - virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const; + 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); - virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const; - virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const; + 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); - virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const; + 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; + 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); - virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const; + 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); - virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID); + 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; + virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; - virtual bool can_any_window_draw() const; + virtual bool can_any_window_draw() const override; - virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID); + 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; + 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); - virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const; + 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 Point2i ime_get_selection() const; - virtual String ime_get_text() const; + virtual Point2i ime_get_selection() const override; + virtual String ime_get_text() const override; - virtual void cursor_set_shape(CursorShape p_shape); - virtual CursorShape cursor_get_shape() const; - virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()); + 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_ok_cancel(); + virtual bool get_swap_cancel_ok() override; - virtual LatinKeyboardVariant get_latin_keyboard_variant() const; + 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 void process_events(); - virtual void force_process_and_drop_events(); + virtual void process_events() override; + virtual void force_process_and_drop_events() override; - virtual void release_rendering_thread(); - virtual void make_rendering_thread(); - virtual void swap_buffers(); + 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); - virtual void set_icon(const Ref<Image> &p_icon); + 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); - virtual bool is_console_visible() const; + 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, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 074fc3be0d..3b82950224 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -45,8 +45,9 @@ #include <IOKit/hid/IOHIDLib.h> #if defined(OPENGL_ENABLED) -#include "drivers/gles2/rasterizer_gles2.h" //TODO - reimplement OpenGLES + +#import <AppKit/NSOpenGLView.h> #endif #if defined(VULKAN_ENABLED) @@ -55,6 +56,10 @@ #include <QuartzCore/CAMetalLayer.h> #endif +#ifndef NSAppKitVersionNumber10_14 +#define NSAppKitVersionNumber10_14 1671 +#endif + #define DS_OSX ((DisplayServerOSX *)(DisplayServerOSX::get_singleton())) static void _get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) { @@ -64,13 +69,13 @@ static void _get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWith r_state->set_metakey((p_osx_state & NSEventModifierFlagCommand)); } -static Vector2i _get_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPoint p_locationInWindow, CGFloat p_backingScaleFactor) { +static Vector2i _get_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPoint p_locationInWindow) { const NSRect contentRect = [p_wd.window_view frame]; - const NSPoint p = p_locationInWindow; - p_wd.mouse_pos.x = p.x * p_backingScaleFactor; - p_wd.mouse_pos.y = (contentRect.size.height - p.y) * p_backingScaleFactor; + 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; - InputFilter::get_singleton()->set_mouse_position(p_wd.mouse_pos); + Input::get_singleton()->set_mouse_position(p_wd.mouse_pos); return p_wd.mouse_pos; } @@ -120,17 +125,18 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { k->set_physical_keycode(KEY_PERIOD); k->set_echo([event isARepeat]); - InputFilter::get_singleton()->accumulate_input_event(k); + Input::get_singleton()->accumulate_input_event(k); } } // 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)) + if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) { [[self keyWindow] sendEvent:event]; - else + } else { [super sendEvent:event]; + } } @end @@ -145,6 +151,7 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { Variant meta; bool checkable; } + @end @implementation GlobalMenuItem @@ -192,9 +199,22 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } } +- (void)applicationDidResignActive:(NSNotification *)notification { + if (OS_OSX::get_singleton()->get_main_loop()) { + OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); + } +} + +- (void)applicationDidBecomeActive:(NSNotification *)notification { + if (OS_OSX::get_singleton()->get_main_loop()) { + OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); + } +} + - (void)globalMenuCallback:(id)sender { - if (![sender representedObject]) + if (![sender representedObject]) { return; + } GlobalMenuItem *value = [sender representedObject]; @@ -247,8 +267,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (void)showAbout:(id)sender { - if (OS_OSX::get_singleton()->get_main_loop()) + if (OS_OSX::get_singleton()->get_main_loop()) { OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT); + } } @end @@ -273,13 +294,17 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (BOOL)windowShouldClose:(id)sender { - ERR_FAIL_COND_V(!DS_OSX->windows.has(window_id), YES); + 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 { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); + if (!DS_OSX || !DS_OSX->windows.has(window_id)) { + return; + } DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; while (wd.transient_children.size()) { @@ -297,6 +322,11 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to main window if there is no parent or other windows left. } +#if defined(OPENGL_ENABLED) + if (DS_OSX->rendering_driver == "opengl_es") { + //TODO - reimplement OpenGLES + } +#endif #ifdef VULKAN_ENABLED if (DS_OSX->rendering_driver == "vulkan") { DS_OSX->context_vulkan->window_destroy(window_id); @@ -305,7 +335,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (void)windowDidEnterFullScreen:(NSNotification *)notification { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); + if (!DS_OSX || !DS_OSX->windows.has(window_id)) { + return; + } DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; wd.fullscreen = true; @@ -315,28 +347,32 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (void)windowDidExitFullScreen:(NSNotification *)notification { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) + 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 / DS_OSX->_display_scale([wd.window_object screen]); + 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 / DS_OSX->_display_scale([wd.window_object screen]); + Size2i size = wd.max_size / scale; [wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)]; } - if (wd.resize_disabled) + if (wd.resize_disabled) { [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable]; + } } - (void)windowDidChangeBackingProperties:(NSNotification *)notification { - if (!DisplayServerOSX::get_singleton()) + if (!DisplayServerOSX::get_singleton()) { return; + } ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; @@ -344,60 +380,50 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { CGFloat newBackingScaleFactor = [wd.window_object backingScaleFactor]; CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; -#if defined(OPENGL_ENABLED) - if (DS_OSX->rendering_driver == "opengl_es") { - //TODO - reimplement OpenGLES - if (OS_OSX::get_singleton()->is_hidpi_allowed()) { - [wd.window_view setWantsBestResolutionOpenGLSurface:YES]; - } else { - [wd.window_view setWantsBestResolutionOpenGLSurface:NO]; - } - } -#endif - if (newBackingScaleFactor != oldBackingScaleFactor) { //Set new display scale and window size - float newDisplayScale = OS_OSX::get_singleton()->is_hidpi_allowed() ? newBackingScaleFactor : 1.0; - + const float scale = DS_OSX->screen_get_max_scale(); const NSRect contentRect = [wd.window_view frame]; - wd.size.width = contentRect.size.width * newDisplayScale; - wd.size.height = contentRect.size.height * newDisplayScale; + 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); -#if defined(VULKAN_ENABLED) - if (DS_OSX->rendering_driver == "vulkan") { - CALayer *layer = [wd.window_view layer]; - layer.contentsScale = DS_OSX->_display_scale([wd.window_object screen]); + CALayer *layer = [wd.window_view layer]; + if (layer) { + layer.contentsScale = scale; } -#endif + //Force window resize event [self windowDidResize:notification]; } } - (void)windowDidResize:(NSNotification *)notification { - if (!DS_OSX || !DS_OSX->windows.has(window_id)) + 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(OPENGL_ENABLED) if (DS_OSX->rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES - wd.context_gles2->update(); } #endif - const NSRect contentRect = [wd.window_view frame]; - - float displayScale = DS_OSX->_display_scale([wd.window_object screen]); - wd.size.width = contentRect.size.width * displayScale; - wd.size.height = contentRect.size.height * displayScale; - #if defined(VULKAN_ENABLED) if (DS_OSX->rendering_driver == "vulkan") { - CALayer *layer = [wd.window_view layer]; - layer.contentsScale = displayScale; DS_OSX->context_vulkan->window_resize(window_id, wd.size.width, wd.size.height); } #endif @@ -420,23 +446,39 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (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 { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); + if (!DS_OSX || !DS_OSX->windows.has(window_id)) { + return; + } DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [wd.window_view backingScaleFactor] : 1.0; - _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream], backingScaleFactor); - InputFilter::get_singleton()->set_mouse_position(wd.mouse_pos); + _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 { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); + if (!DS_OSX || !DS_OSX->windows.has(window_id)) { + return; + } DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; DS_OSX->window_focused = false; @@ -446,7 +488,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (void)windowDidMiniaturize:(NSNotification *)notification { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); + if (!DS_OSX || !DS_OSX->windows.has(window_id)) { + return; + } DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; DS_OSX->window_focused = false; @@ -456,7 +500,9 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (void)windowDidDeminiaturize:(NSNotification *)notification { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); + if (!DS_OSX || !DS_OSX->windows.has(window_id)) { + return; + } DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; DS_OSX->window_focused = true; @@ -497,6 +543,12 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (CALayer *)makeBackingLayer { +#if defined(OPENGL_ENABLED) + if (DS_OSX->rendering_driver == "opengl_es") { + CALayer *layer = [[NSOpenGLLayer class] layer]; + return layer; + } +#endif #if defined(VULKAN_ENABLED) if (DS_OSX->rendering_driver == "vulkan") { CALayer *layer = [[CAMetalLayer class] layer]; @@ -507,20 +559,17 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (void)updateLayer { -#if defined(VULKAN_ENABLED) - if (DS_OSX->rendering_driver == "vulkan") { - [super updateLayer]; - } -#endif #if defined(OPENGL_ENABLED) if (DS_OSX->rendering_driver == "opengl_es") { - ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); - DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - - wd.context_gles2->update(); + [super updateLayer]; //TODO - reimplement OpenGLES } #endif +#if defined(VULKAN_ENABLED) + if (DS_OSX->rendering_driver == "vulkan") { + [super updateLayer]; + } +#endif } - (BOOL)wantsUpdateLayer { @@ -532,7 +581,11 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { 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; } @@ -581,8 +634,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; } - (void)doCommandBySelector:(SEL)aSelector { - if ([self respondsToSelector:aSelector]) + if ([self respondsToSelector:aSelector]) { [self performSelector:aSelector]; + } } - (void)unmarkText { @@ -617,8 +671,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; const NSRect contentRect = [wd.window_view frame]; - float displayScale = DS_OSX->_display_scale([wd.window_object screen]); - NSRect pointInWindowRect = NSMakeRect(wd.im_position.x / displayScale, contentRect.size.height - (wd.im_position.y / displayScale) - 1, 0, 0); + 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); @@ -657,8 +711,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; for (i = 0; i < length; i++) { const unichar codepoint = [characters characterAtIndex:i]; - if ((codepoint & 0xFF00) == 0xF700) + if ((codepoint & 0xFF00) == 0xF700) { continue; + } DisplayServerOSX::KeyEvent ke; @@ -689,11 +744,19 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; NSPasteboard *pboard = [sender draggingPasteboard]; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 + NSArray<NSURL *> *filenames = [pboard propertyListForType:NSPasteboardTypeFileURL]; +#else NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; +#endif Vector<String> files; for (NSUInteger i = 0; i < filenames.count; i++) { +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 + NSString *ns = [[filenames objectAtIndex:i] path]; +#else NSString *ns = [filenames objectAtIndex:i]; +#endif char *utfs = strdup([ns UTF8String]); String ret; ret.parse_utf8(utfs); @@ -717,6 +780,12 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; } - (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; } @@ -743,8 +812,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i Ref<InputEventMouseButton> mb; mb.instance(); mb->set_window_id(window_id); - const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0; - const Vector2 pos = _get_mouse_pos(wd, [event locationInWindow], backingScaleFactor); + 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); @@ -755,7 +823,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i mb->set_doubleclick([event clickCount] == 2); } - InputFilter::get_singleton()->accumulate_input_event(mb); + Input::get_singleton()->accumulate_input_event(mb); } - (void)mouseDown:(NSEvent *)event { @@ -790,13 +858,58 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i 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->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED) { + // 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.instance(); mm->set_window_id(window_id); mm->set_button_mask(DS_OSX->last_button_state); - const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0; - const Vector2i pos = _get_mouse_pos(wd, [event locationInWindow], backingScaleFactor); + const Vector2i pos = _get_mouse_pos(wd, mpos); mm->set_position(pos); mm->set_pressure([event pressure]); if ([event subtype] == NSEventSubtypeTabletPoint) { @@ -804,15 +917,13 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i mm->set_tilt(Vector2(p.x, p.y)); } mm->set_global_position(pos); - mm->set_speed(InputFilter::get_singleton()->get_last_mouse_speed()); - Vector2i relativeMotion = Vector2i(); - relativeMotion.x = [event deltaX] * backingScaleFactor; - relativeMotion.y = [event deltaY] * backingScaleFactor; + 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); - InputFilter::get_singleton()->set_mouse_position(wd.mouse_pos); - InputFilter::get_singleton()->accumulate_input_event(mm); + Input::get_singleton()->set_mouse_position(wd.mouse_pos); + Input::get_singleton()->accumulate_input_event(mm); } - (void)rightMouseDown:(NSEvent *)event { @@ -859,16 +970,18 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i 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) + 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) + 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; @@ -883,11 +996,10 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i ev.instance(); ev->set_window_id(window_id); _get_key_modifier_state([event modifierFlags], ev); - const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0; - ev->set_position(_get_mouse_pos(wd, [event locationInWindow], backingScaleFactor)); + ev->set_position(_get_mouse_pos(wd, [event locationInWindow])); ev->set_factor([event magnification] + 1.0); - InputFilter::get_singleton()->accumulate_input_event(ev); + Input::get_singleton()->accumulate_input_event(ev); } - (void)viewDidChangeBackingProperties { @@ -900,24 +1012,14 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i [trackingArea release]; } - NSTrackingAreaOptions options = - NSTrackingMouseEnteredAndExited | - NSTrackingActiveInKeyWindow | - NSTrackingCursorUpdate | - NSTrackingInVisibleRect; - - trackingArea = [[NSTrackingArea alloc] - initWithRect:[self bounds] - options:options - owner:self - userInfo:nil]; + 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 */ @@ -941,8 +1043,9 @@ static bool isNumpadKey(unsigned int key) { 0x00 }; for (int i = 0; table[i] != 0; i++) { - if (key == table[i]) + if (key == table[i]) { return true; + } } return false; } @@ -950,7 +1053,6 @@ static bool isNumpadKey(unsigned int key) { // Translates a OS X keycode to a Godot keycode // static int translateKey(unsigned int key) { - // Keyboard symbol translation table static const unsigned int table[128] = { /* 00 */ KEY_A, @@ -1083,8 +1185,9 @@ static int translateKey(unsigned int key) { /* 7f */ KEY_UNKNOWN, }; - if (key >= 128) + if (key >= 128) { return KEY_UNKNOWN; + } return table[key]; } @@ -1153,16 +1256,19 @@ static const _KeyCodeMap _keycodes[55] = { }; static int remapKey(unsigned int key, unsigned int state) { - if (isNumpadKey(key)) + if (isNumpadKey(key)) { return translateKey(key); + } TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); - if (!currentKeyboard) + if (!currentKeyboard) { return translateKey(key); + } CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); - if (!layoutData) + if (!layoutData) { return translateKey(key); + } const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); @@ -1235,8 +1341,9 @@ static int remapKey(unsigned int key, unsigned int state) { } // Pass events to IME handler - if (wd.im_active) + if (wd.im_active) { [self interpretKeyEvents:[NSArray arrayWithObject:event]]; + } } - (void)flagsChanged:(NSEvent *)event { @@ -1353,7 +1460,7 @@ inline void sendScrollEvent(DisplayServer::WindowID window_id, int button, doubl DS_OSX->last_button_state |= mask; sc->set_button_mask(DS_OSX->last_button_state); - InputFilter::get_singleton()->accumulate_input_event(sc); + Input::get_singleton()->accumulate_input_event(sc); sc.instance(); sc->set_window_id(window_id); @@ -1365,7 +1472,7 @@ inline void sendScrollEvent(DisplayServer::WindowID window_id, int button, doubl DS_OSX->last_button_state &= ~mask; sc->set_button_mask(DS_OSX->last_button_state); - InputFilter::get_singleton()->accumulate_input_event(sc); + Input::get_singleton()->accumulate_input_event(sc); } inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy, int modifierFlags) { @@ -1380,7 +1487,7 @@ inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy pg->set_position(wd.mouse_pos); pg->set_delta(Vector2(-dx, -dy)); - InputFilter::get_singleton()->accumulate_input_event(pg); + Input::get_singleton()->accumulate_input_event(pg); } - (void)scrollWheel:(NSEvent *)event { @@ -1389,8 +1496,7 @@ inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy double deltaX, deltaY; - const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0; - _get_mouse_pos(wd, [event locationInWindow], backingScaleFactor); + _get_mouse_pos(wd, [event locationInWindow]); deltaX = [event scrollingDeltaX]; deltaY = [event scrollingDeltaY]; @@ -1420,12 +1526,32 @@ inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy @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; } @@ -1452,6 +1578,7 @@ bool DisplayServerOSX::has_feature(Feature p_feature) const { case FEATURE_HIDPI: case FEATURE_ICON: case FEATURE_NATIVE_ICON: + //case FEATURE_KEEP_SCREEN_ON: case FEATURE_SWAP_BUFFERS: return true; default: { @@ -1652,7 +1779,8 @@ String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, 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(); + if (E->get() == sub_menu) + return E->key(); } } } @@ -1815,8 +1943,12 @@ void DisplayServerOSX::alert(const String &p_alert, const String &p_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]; + } } Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { @@ -1896,23 +2028,32 @@ Error DisplayServerOSX::dialog_input_text(String p_title, String p_description, void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) { _THREAD_SAFE_METHOD_ - if (p_mode == mouse_mode) + if (p_mode == mouse_mode) { return; + } 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 - CGDisplayHideCursor(kCGDirectMainDisplay); + if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { + CGDisplayHideCursor(kCGDirectMainDisplay); + } CGAssociateMouseAndMouseCursorPosition(false); } else if (p_mode == MOUSE_MODE_HIDDEN) { - CGDisplayHideCursor(kCGDirectMainDisplay); + if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { + CGDisplayHideCursor(kCGDirectMainDisplay); + } CGAssociateMouseAndMouseCursorPosition(true); + } else if (p_mode == MOUSE_MODE_CONFINED) { + CGDisplayShowCursor(kCGDirectMainDisplay); + CGAssociateMouseAndMouseCursorPosition(false); } else { CGDisplayShowCursor(kCGDirectMainDisplay); CGAssociateMouseAndMouseCursorPosition(true); } + warp_events.clear(); mouse_mode = p_mode; } @@ -1930,8 +2071,8 @@ void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) { //local point in window coords const NSRect contentRect = [wd.window_view frame]; - float displayScale = _display_scale([wd.window_object screen]); - NSRect pointInWindowRect = NSMakeRect(p_to.x / displayScale, contentRect.size.height - (p_to.y / displayScale) - 1, 0, 0); + 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 @@ -1942,7 +2083,9 @@ void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) { CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0); CGAssociateMouseAndMouseCursorPosition(false); CGWarpMouseCursorPosition(lMouseWarpPos); - CGAssociateMouseAndMouseCursorPosition(true); + if (mouse_mode != MOUSE_MODE_CONFINED) { + CGAssociateMouseAndMouseCursorPosition(true); + } } } @@ -1954,11 +2097,12 @@ 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) + _get_screens_origin(); + return Vector2i((int)mouse_pos.x, (int)-mouse_pos.y) * scale + _get_screens_origin(); } } return Vector2i(); @@ -2016,17 +2160,10 @@ int DisplayServerOSX::get_screen_count() const { // 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; -} - -float DisplayServerOSX::_display_scale(id screen) const { - if (OS_OSX::get_singleton()->is_hidpi_allowed()) { - if ([screen respondsToSelector:@selector(backingScaleFactor)]) { - return fmax(1.0, [screen backingScaleFactor]); - } - } - return 1.0; + displays_scale_dirty = true; } Point2i DisplayServerOSX::_get_screens_origin() const { @@ -2053,10 +2190,9 @@ Point2i DisplayServerOSX::_get_screens_origin() const { Point2i DisplayServerOSX::_get_native_screen_position(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if ((NSUInteger)p_screen < [screenArray count]) { - float display_scale = _display_scale([screenArray objectAtIndex:p_screen]); 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) * display_scale; + return Point2i(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * screen_get_max_scale(); } return Point2i(); @@ -2085,10 +2221,9 @@ Size2i DisplayServerOSX::screen_get_size(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if ((NSUInteger)p_screen < [screenArray count]) { - float displayScale = _display_scale([screenArray objectAtIndex:p_screen]); // Note: Use frame to get the whole screen size NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame]; - return Size2i(nsrect.size.width, nsrect.size.height) * displayScale; + return Size2i(nsrect.size.width, nsrect.size.height) * screen_get_max_scale(); } return Size2i(); @@ -2103,13 +2238,9 @@ int DisplayServerOSX::screen_get_dpi(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if ((NSUInteger)p_screen < [screenArray count]) { - float displayScale = _display_scale([screenArray objectAtIndex:p_screen]); NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription]; - NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue]; - CGSize displayPhysicalSize = CGDisplayScreenSize( - [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); - - return (displayPixelSize.width * 25.4f / displayPhysicalSize.width) * displayScale; + NSSize displayDPI = [[description objectForKey:NSDeviceResolution] sizeValue]; + return (displayDPI.width + displayDPI.height) / 2; } return 96; @@ -2121,14 +2252,32 @@ float DisplayServerOSX::screen_get_scale(int p_screen) const { if (p_screen == SCREEN_OF_MAIN_WINDOW) { p_screen = window_get_current_screen(); } - NSArray *screenArray = [NSScreen screens]; - if ((NSUInteger)p_screen < [screenArray count]) { - return _display_scale([screenArray objectAtIndex:p_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_ @@ -2138,12 +2287,12 @@ Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if ((NSUInteger)p_screen < [screenArray count]) { - float displayScale = _display_scale([screenArray objectAtIndex:p_screen]); + 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) * displayScale - _get_screens_origin(); + 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) / displayScale; + Size2i size = Size2i(nsrect.size.width, nsrect.size.height) * scale; return Rect2i(position, size); } @@ -2165,16 +2314,25 @@ DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, u _THREAD_SAFE_METHOD_ WindowID id = _create_window(p_mode, p_rect); - WindowData &wd = windows[id]; for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, id); } } - [wd.window_object makeKeyAndOrderFront:nil]; + 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_ @@ -2189,8 +2347,9 @@ void DisplayServerOSX::_send_window_event(const WindowData &wd, WindowEvent p_ev 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) + if (E->get().window_object == p_window) { return E->key(); + } } return INVALID_WINDOW_ID; } @@ -2314,7 +2473,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent wd_window.transient_parent = INVALID_WINDOW_ID; wd_parent.transient_children.erase(p_window); - [wd_window.window_object setParentWindow:nil]; + [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"); @@ -2323,7 +2482,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent wd_window.transient_parent = p_parent; wd_parent.transient_children.insert(p_window); - [wd_window.window_object setParentWindow:wd_parent.window_object]; + [wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove]; } } @@ -2335,11 +2494,12 @@ Point2i DisplayServerOSX::window_get_position(WindowID p_window) const { NSRect nsrect = [wd.window_object frame]; Point2i pos; - float display_scale = _display_scale([wd.window_object screen]); // Return the position of the top-left corner, for OS X the y starts at the bottom - pos.x = nsrect.origin.x * display_scale; - pos.y = (nsrect.origin.y + nsrect.size.height) * display_scale; + 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 @@ -2358,17 +2518,12 @@ void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p // Godot passes a positive value position.y *= -1; position += _get_screens_origin(); + position /= screen_get_max_scale(); - NSPoint pos; - float displayScale = _display_scale([wd.window_object screen]); - - pos.x = position.x / displayScale; - pos.y = position.y / displayScale; - - [wd.window_object setFrameTopLeftPoint:pos]; + [wd.window_object setFrameTopLeftPoint:NSMakePoint(position.x, position.y)]; _update_window(wd); - _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream], displayScale); + _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); } void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_window) { @@ -2384,7 +2539,7 @@ void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_windo wd.max_size = p_size; if ((wd.max_size != Size2i()) && !wd.fullscreen) { - Size2i size = wd.max_size / _display_scale([wd.window_object screen]); + 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)]; @@ -2412,7 +2567,7 @@ void DisplayServerOSX::window_set_min_size(const Size2i p_size, WindowID p_windo wd.min_size = p_size; if ((wd.min_size != Size2i()) && !wd.fullscreen) { - Size2i size = wd.min_size / _display_scale([wd.window_object screen]); + 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)]; @@ -2434,18 +2589,20 @@ void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - Size2i size = p_size / _display_scale([wd.window_object screen]); + Size2i size = p_size / screen_get_max_scale(); - if (!wd.borderless) { - // NSRect used by setFrame includes the title bar, so add it to our size.y - CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; - if (menuBarHeight != 0.f) { - size.y += menuBarHeight; - } - } + NSPoint top_left; + NSRect old_frame = [wd.window_object frame]; + top_left.x = old_frame.origin.x; + top_left.y = NSMaxY(old_frame); - NSRect frame = [wd.window_object frame]; - [wd.window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, size.x, size.y) display:YES]; + 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); } @@ -2464,7 +2621,7 @@ Size2i DisplayServerOSX::window_get_real_size(WindowID p_window) const { 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) * _display_scale([wd.window_object screen]); + return Size2i(frame.size.width, frame.size.height) * screen_get_max_scale(); } bool DisplayServerOSX::window_is_maximize_allowed(WindowID p_window) const { @@ -2475,23 +2632,26 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - if (!OS_OSX::get_singleton()->is_layered_allowed()) return; + 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") { - CALayer *layer = [wd.window_view layer]; - [layer setOpaque:NO]; //TODO - implement transparency for Vulkan } #endif #if defined(OPENGL_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES - wd.context_gles2->set_opacity(0); } #endif wd.layered_window = true; @@ -2499,17 +2659,18 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled [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") { - CALayer *layer = [wd.window_view layer]; - [layer setOpaque:YES]; //TODO - implement transparency for Vulkan } #endif #if defined(OPENGL_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES - wd.context_gles2->set_opacity(1); } #endif wd.layered_window = false; @@ -2517,7 +2678,11 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled #if defined(OPENGL_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES - wd.context_gles2->update(); + } +#endif +#if defined(VULKAN_ENABLED) + if (rendering_driver == "vulkan") { + //TODO - implement transparency for Vulkan } #endif NSRect frameRect = [wd.window_object frame]; @@ -2545,16 +2710,18 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { [wd.window_object deminiaturize:nil]; } break; case WINDOW_MODE_FULLSCREEN: { - if (wd.layered_window) + if (wd.layered_window) { _set_window_per_pixel_transparency_enabled(true, p_window); - if (wd.resize_disabled) //restore resize disabled + } + 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 / _display_scale([wd.window_object screen]); + 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 / _display_scale([wd.window_object screen]); + Size2i size = wd.max_size / screen_get_max_scale(); [wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)]; } [wd.window_object toggleFullScreen:nil]; @@ -2623,8 +2790,9 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo switch (p_flag) { case WINDOW_FLAG_RESIZE_DISABLED: { wd.resize_disabled = p_enabled; - if (wd.fullscreen) //fullscreen window should be resizable, style will be applyed on exiting fs + 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 { @@ -2633,7 +2801,9 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } break; case WINDOW_FLAG_BORDERLESS: { // OrderOut prevents a lose focus bug with the window - [wd.window_object orderOut:nil]; + if ([wd.window_object isVisible]) { + [wd.window_object orderOut:nil]; + } wd.borderless = p_enabled; if (p_enabled) { [wd.window_object setStyleMask:NSWindowStyleMaskBorderless]; @@ -2647,7 +2817,13 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo [wd.window_object setFrame:frameRect display:NO]; } _update_window(wd); - [wd.window_object makeKeyAndOrderFront:nil]; + 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; @@ -2665,7 +2841,9 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo [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: { } @@ -2691,6 +2869,9 @@ bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) co case WINDOW_FLAG_TRANSPARENT: { return wd.layered_window; } break; + case WINDOW_FLAG_NO_FOCUS: { + return wd.no_focus; + } break; default: { } } @@ -2710,7 +2891,11 @@ void DisplayServerOSX::window_move_to_foreground(WindowID p_window) { const WindowData &wd = windows[p_window]; [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [wd.window_object makeKeyAndOrderFront:nil]; + if (wd.no_focus) { + [wd.window_object orderFront:nil]; + } else { + [wd.window_object makeKeyAndOrderFront:nil]; + } } bool DisplayServerOSX::window_can_draw(WindowID p_window) const { @@ -2736,8 +2921,9 @@ void DisplayServerOSX::window_set_ime_active(const bool p_active, WindowID p_win wd.im_active = p_active; - if (!p_active) + if (!p_active) { [wd.window_view cancelComposition]; + } } void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_window) { @@ -2749,8 +2935,8 @@ void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_ wd.im_position = p_pos; } -bool DisplayServerOSX::get_swap_ok_cancel() { - return true; +bool DisplayServerOSX::get_swap_cancel_ok() { + return false; } void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { @@ -2758,8 +2944,9 @@ void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { ERR_FAIL_INDEX(p_shape, CURSOR_MAX); - if (cursor_shape == p_shape) + if (cursor_shape == p_shape) { return; + } if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) { cursor_shape = p_shape; @@ -2770,23 +2957,57 @@ void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { [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; + 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: { } } @@ -2918,97 +3139,140 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape } } +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; } -// Returns string representation of keys, if they are printable. -static NSString *createStringForKeys(const CGKeyCode *keyCode, int length) { - TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); - if (!currentKeyboard) - return nil; +void _update_keyboard_layouts() { + @autoreleasepool { + TISInputSourceRef cur_source = TISCopyCurrentKeyboardInputSource(); + NSString *cur_name = (NSString *)TISGetInputSourceProperty(cur_source, kTISPropertyLocalizedName); + CFRelease(cur_source); - CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); - if (!layoutData) - return nil; + // 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]); - const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); + NSArray *langs = (NSArray *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyInputSourceLanguages); + ly.code.parse_utf8([(NSString *)[langs objectAtIndex:0] UTF8String]); + kbd_layouts.push_back(ly); - OSStatus err; - CFMutableStringRef output = CFStringCreateMutable(NULL, 0); + if ([name isEqualToString:cur_name]) { + current_layout = kbd_layouts.size() - 1; + } + } + [list_ime release]; - for (int i = 0; i < length; ++i) { - UInt32 keysDown = 0; - UniChar chars[4]; - UniCharCount realLength; + // 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]); - err = UCKeyTranslate(keyboardLayout, - keyCode[i], - kUCKeyActionDisplay, - 0, - LMGetKbdType(), - kUCKeyTranslateNoDeadKeysBit, - &keysDown, - sizeof(chars) / sizeof(chars[0]), - &realLength, - chars); + 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 (err != noErr) { - CFRelease(output); - return nil; + if ([name isEqualToString:cur_name]) { + current_layout = kbd_layouts.size() - 1; + } } - - CFStringAppendCharacters(output, chars, 1); + [list_kbd release]; } - return (NSString *)output; + keyboard_layout_dirty = false; } -DisplayServerOSX::LatinKeyboardVariant DisplayServerOSX::get_latin_keyboard_variant() const { - _THREAD_SAFE_METHOD_ - - static LatinKeyboardVariant layout = LATIN_KEYBOARD_QWERTY; +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(); + } - layout = LATIN_KEYBOARD_QWERTY; + ERR_FAIL_INDEX(p_index, kbd_layouts.size()); - CGKeyCode keys[] = { kVK_ANSI_Q, kVK_ANSI_W, kVK_ANSI_E, kVK_ANSI_R, kVK_ANSI_T, kVK_ANSI_Y }; - NSString *test = createStringForKeys(keys, 6); + NSString *cur_name = [NSString stringWithUTF8String:kbd_layouts[p_index].name.utf8().get_data()]; - if ([test isEqualToString:@"qwertz"]) { - layout = LATIN_KEYBOARD_QWERTZ; - } else if ([test isEqualToString:@"azerty"]) { - layout = LATIN_KEYBOARD_AZERTY; - } else if ([test isEqualToString:@"qzerty"]) { - layout = LATIN_KEYBOARD_QZERTY; - } else if ([test isEqualToString:@"',.pyf"]) { - layout = LATIN_KEYBOARD_DVORAK; - } else if ([test isEqualToString:@"xvlcwk"]) { - layout = LATIN_KEYBOARD_NEO; - } else if ([test isEqualToString:@"qwfpgj"]) { - layout = LATIN_KEYBOARD_COLEMAK; + 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]; - [test 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]; +} - keyboard_layout_dirty = false; - return layout; +int DisplayServerOSX::keyboard_get_current_layout() const { + if (keyboard_layout_dirty) { + _update_keyboard_layouts(); } - return layout; + 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; } void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) { Ref<InputEvent> ev = p_event; - InputFilter::get_singleton()->accumulate_input_event(ev); + Input::get_singleton()->accumulate_input_event(ev); } void DisplayServerOSX::_release_pressed_events() { _THREAD_SAFE_METHOD_ - if (InputFilter::get_singleton()) { - InputFilter::get_singleton()->release_pressed_events(); + if (Input::get_singleton()) { + Input::get_singleton()->release_pressed_events(); } } @@ -3076,15 +3340,16 @@ void DisplayServerOSX::process_events() { inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event == nil) + if (event == nil) { break; + } [NSApp sendEvent:event]; } if (!drop_events) { _process_key_events(); - InputFilter::get_singleton()->flush_accumulated_events(); + Input::get_singleton()->flush_accumulated_events(); } [autoreleasePool drain]; @@ -3165,11 +3430,11 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { Vector<String> DisplayServerOSX::get_rendering_drivers_func() { Vector<String> drivers; -#ifdef VULKAN_ENABLED +#if defined(VULKAN_ENABLED) drivers.push_back("vulkan"); #endif -#ifdef OPENGL_ENABLED - drivers.push_back("opengl"); +#if defined(OPENGL_ENABLED) + drivers.push_back("opengl_es"); #endif return drivers; @@ -3184,9 +3449,14 @@ String DisplayServerOSX::ime_get_text() const { } 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()) { - Rect2i win_rect = Rect2i(window_get_position(E->key()), window_get_size(E->key())); - if (win_rect.has_point(p_position)) { + if ([E->get().window_object windowNumber] == wnum) { return E->key(); } } @@ -3208,23 +3478,19 @@ ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) co } DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - return memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); + DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); + if (r_error != OK) { + ds->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver"); + } + return ds; } DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, const Rect2i &p_rect) { WindowID id; + const float scale = screen_get_max_scale(); { WindowData wd; - float displayScale = 1.0; - if (OS_OSX::get_singleton()->is_hidpi_allowed()) { - // note that mainScreen is not screen #0 but the one with the keyboard focus. - NSScreen *screen = [NSScreen mainScreen]; - if ([screen respondsToSelector:@selector(backingScaleFactor)]) { - displayScale = fmax(displayScale, [screen backingScaleFactor]); - } - } - 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]; @@ -3237,7 +3503,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, c // initWithContentRect uses bottom-left corner of the window’s frame as origin. wd.window_object = [[GodotWindow alloc] - initWithContentRect:NSMakeRect(position.x / displayScale, (position.y - p_rect.size.height) / displayScale, p_rect.size.width / displayScale, p_rect.size.height / displayScale) + 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]; @@ -3246,24 +3512,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, c 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]; - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_14) { - [wd.window_view setWantsLayer:TRUE]; - } - - if (displayScale > 1.0) { -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { - [wd.window_view setWantsBestResolutionOpenGLSurface:YES]; - } -#endif - [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - } else { -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { - [wd.window_view setWantsBestResolutionOpenGLSurface:NO]; - } -#endif - } + [wd.window_view setWantsLayer:TRUE]; [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; [wd.window_object setContentView:wd.window_view]; @@ -3271,33 +3520,26 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, c [wd.window_object setAcceptsMouseMovedEvents:YES]; [wd.window_object setRestorable:NO]; - if ([wd.window_object respondsToSelector:@selector(setTabbingMode:)]) + 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) { - CALayer *layer = [wd.window_view layer]; - layer.contentsScale = displayScale; Error err = context_vulkan->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 a Vulkan context"); } } #endif -#ifdef OPENGL_ENABLED +#if defined(OPENGL_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES - wd.context_gles2 = memnew(ContextGL_OSX(wd.window_view, false)); - - if (wd.context_gles2->initialize() != OK) { - memdelete(wd.context_gles2); - ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a OpenGL context"); - } - - //if (RasterizerGLES2::is_viable() == OK) { - // RasterizerGLES2::register_config(); - // RasterizerGLES2::make_current(); - //} } #endif id = window_id_counter++; @@ -3307,25 +3549,22 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, c WindowData &wd = windows[id]; window_set_mode(p_mode, id); - float displayScale = _display_scale([wd.window_object screen]); const NSRect contentRect = [wd.window_view frame]; - wd.size.width = contentRect.size.width * displayScale; - wd.size.height = contentRect.size.height * displayScale; + 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(OPENGL_ENABLED) if (rendering_driver == "opengl_es") { - if (OS_OSX::singleton->is_hidpi_allowed()) { - [wd.window_view setWantsBestResolutionOpenGLSurface:YES]; - } else { - [wd.window_view setWantsBestResolutionOpenGLSurface:NO]; - } - wd.context_gles2->update(); + //TODO - reimplement OpenGLES } #endif #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { - CALayer *layer = [wd.window_view layer]; - layer.contentsScale = displayScale; context_vulkan->window_resize(id, wd.size.width, wd.size.height); } #endif @@ -3393,7 +3632,7 @@ bool DisplayServerOSX::is_console_visible() const { } DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - InputFilter::get_singleton()->set_event_dispatch_function(_dispatch_input_events); + Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); r_error = OK; drop_events = false; @@ -3420,6 +3659,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode keyboard_layout_dirty = true; displays_arrangement_dirty = true; + displays_scale_dirty = true; // Register to be notified on keyboard layout changes CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), @@ -3437,8 +3677,9 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode NSString *title; NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; - if (nsappname == nil) + if (nsappname == nil) { nsappname = [[NSProcessInfo processInfo] processName]; + } // Setup Dock menu dock_menu = [[NSMenu alloc] initWithTitle:@"_dock"]; @@ -3491,8 +3732,9 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event == nil) + if (event == nil) { break; + } [NSApp sendEvent:event]; } @@ -3513,7 +3755,6 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode #endif #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { - context_vulkan = memnew(VulkanContextOSX); if (context_vulkan->initialize() != OK) { memdelete(context_vulkan); @@ -3524,14 +3765,23 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode } #endif - WindowID main_window = _create_window(p_mode, Rect2i(Point2i(), p_resolution)); + 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, 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); } } - [windows[main_window].window_object makeKeyAndOrderFront:nil]; + show_window(MAIN_WINDOW_ID); +#if defined(OPENGL_ENABLED) + if (rendering_driver == "opengl_es") { + //TODO - reimplement OpenGLES + } +#endif #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { rendering_device_vulkan = memnew(RenderingDeviceVulkan); @@ -3542,14 +3792,6 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode #endif [NSApp activateIgnoringOtherApps:YES]; - - /* - visual_server = memnew(VisualServerRaster); - if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { - visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); - } - visual_server->init(); - */ } DisplayServerOSX::~DisplayServerOSX() { @@ -3568,16 +3810,21 @@ DisplayServerOSX::~DisplayServerOSX() { } //destroy drivers +#if defined(OPENGL_ENABLED) + if (rendering_driver == "opengl_es") { + //TODO - reimplement OpenGLES + } +#endif #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { - if (rendering_device_vulkan) { rendering_device_vulkan->finalize(); memdelete(rendering_device_vulkan); } - if (context_vulkan) + if (context_vulkan) { memdelete(context_vulkan); + } } #endif @@ -3585,9 +3832,6 @@ DisplayServerOSX::~DisplayServerOSX() { CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL); cursors_cache.clear(); - - //visual_server->finish(); - //memdelete(visual_server); } void DisplayServerOSX::register_osx_driver() { diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index c2df9c7082..0cf02ef69b 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -46,7 +46,6 @@ #include <sys/stat.h> class EditorExportPlatformOSX : public EditorExportPlatform { - GDCLASS(EditorExportPlatformOSX, EditorExportPlatform); int version_code; @@ -56,8 +55,10 @@ class EditorExportPlatformOSX : public EditorExportPlatform { 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); 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; } @@ -66,17 +67,39 @@ class EditorExportPlatformOSX : public EditorExportPlatform { 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++) { + CharType 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); - virtual void get_export_options(List<ExportOption> *r_options); + 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 { return "Mac OSX"; } - virtual String get_os_name() const { return "OSX"; } - virtual Ref<Texture2D> get_logo() const { return logo; } + 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 { + virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override { List<String> list; if (use_dmg()) { list.push_back("dmg"); @@ -84,18 +107,17 @@ public: 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); - - virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; - virtual void get_platform_features(List<String> *r_features) { + 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("OSX"); } - virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) { + virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override { } EditorExportPlatformOSX(); @@ -117,14 +139,13 @@ void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> } 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/identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); + 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/short_version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); @@ -140,6 +161,11 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "")); 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)); @@ -148,7 +174,6 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) } 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; @@ -163,7 +188,6 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, 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); @@ -215,7 +239,6 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, } void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { - Ref<ImageTexture> it = memnew(ImageTexture); Vector<uint8_t> data; @@ -320,7 +343,6 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ } 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()); @@ -332,8 +354,8 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset 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("$identifier") != -1) { - strnew += lines[i].replace("$identifier", p_preset->get("application/identifier")) + "\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) { @@ -369,7 +391,54 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset - 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, true, nullptr, &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) { +#ifdef OSX_ENABLED List<String> args; if (p_preset->get("codesign/timestamp")) { @@ -380,8 +449,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese args.push_back("runtime"); } - if (p_preset->get("codesign/entitlements") != "") { - /* this should point to our entitlements.plist file that sandboxes our application, I don't know if this should also be placed in our app bundle */ + if ((p_preset->get("codesign/entitlements") != "") && (p_path.get_extension() != "dmg")) { args.push_back("--entitlements"); args.push_back(p_preset->get("codesign/entitlements")); } @@ -405,7 +473,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese Error err = OS::get_singleton()->execute("codesign", args, true, nullptr, &str, nullptr, true); ERR_FAIL_COND_V(err != OK, err); - print_line("codesign (" + p_path + "): " + str); + print_line("codesign (" + p_path + "):\n" + str); if (str.find("no identity found") != -1) { EditorNode::add_io_error("codesign: no identity found"); return FAILED; @@ -414,6 +482,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese EditorNode::add_io_error("codesign: invalid entitlements file"); return FAILED; } +#endif return OK; } @@ -458,10 +527,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p EditorProgress ep("export", "Exporting for OSX", 3, true); - if (p_debug) + if (p_debug) { src_pkg_name = p_preset->get("custom_template/debug"); - else + } else { src_pkg_name = p_preset->get("custom_template/release"); + } if (src_pkg_name == "") { String err; @@ -485,7 +555,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p 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; } @@ -495,64 +564,54 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".64"; String pkg_name; - if (p_preset->get("application/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")) != "") + } else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); - else + } else { pkg_name = "Unnamed"; + } String pkg_name_safe = OS::get_singleton()->get_safe_dir_name(pkg_name); Error err = OK; String tmp_app_path_name = ""; - zlib_filefunc_def io2 = io; - FileAccess *dst_f = nullptr; - io2.opaque = &dst_f; - zipFile dst_pkg_zip = nullptr; DirAccess *tmp_app_path = nullptr; String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip"; - if (export_format == "dmg") { - // We're on OSX so we can export to DMG, but first we create our application bundle - tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app"); - print_line("Exporting to " + tmp_app_path_name); - tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); - if (!tmp_app_path) { - err = ERR_CANT_CREATE; - } - // Create our folder structure or rely on unzip? - if (err == OK) { - print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); - err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS"); - } + // Create our application bundle. + tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app"); + print_line("Exporting to " + tmp_app_path_name); + tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); + if (!tmp_app_path) { + err = ERR_CANT_CREATE; + } - if (err == OK) { - print_line("Creating " + tmp_app_path_name + "/Contents/Frameworks"); - err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks"); - } + // Create our folder structure. + if (err == OK) { + print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); + err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS"); + } - if (err == OK) { - print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); - err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); - } - } else { - // Open our destination zip file - dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2); - if (!dst_pkg_zip) { - err = ERR_CANT_CREATE; - } + if (err == OK) { + print_line("Creating " + tmp_app_path_name + "/Contents/Frameworks"); + err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks"); } - // Now process our template + if (err == OK) { + print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); + err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); + } + + // Now process our template. bool found_binary = false; int total_size = 0; while (ret == UNZ_OK && err == OK) { bool is_execute = false; - //get filename + // Get filename. unz_file_info info; char fname[16384]; ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0); @@ -562,13 +621,12 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Vector<uint8_t> data; data.resize(info.uncompressed_size); - //read + // Read. unzOpenCurrentFile(src_pkg_zip); unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size()); unzCloseCurrentFile(src_pkg_zip); - //write - + // Write. file = file.replace_first("osx_template.app/", ""); if (file == "Contents/Info.plist") { @@ -578,7 +636,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (file.begins_with("Contents/MacOS/godot_")) { if (file != "Contents/MacOS/" + binary_to_use) { ret = unzGoToNextFile(src_pkg_zip); - continue; //ignore! + continue; // skip } found_binary = true; is_execute = true; @@ -586,12 +644,13 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } if (file == "Contents/Resources/icon.icns") { - //see if there is an icon + // See if there is an icon. String iconpath; - if (p_preset->get("application/icon") != "") + if (p_preset->get("application/icon") != "") { iconpath = p_preset->get("application/icon"); - else + } else { iconpath = ProjectSettings::get_singleton()->get("application/config/icon"); + } if (iconpath != "") { if (iconpath.get_extension() == "icns") { @@ -614,18 +673,17 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } if (data.size() > 0) { - if (file.find("/data.mono.osx.64.release_debug/") != -1) { if (!p_debug) { ret = unzGoToNextFile(src_pkg_zip); - continue; //skip + continue; // skip } file = file.replace("/data.mono.osx.64.release_debug/", "/data_" + pkg_name_safe + "/"); } if (file.find("/data.mono.osx.64.release/") != -1) { if (p_debug) { ret = unzGoToNextFile(src_pkg_zip); - continue; //skip + continue; // skip } file = file.replace("/data.mono.osx.64.release/", "/data_" + pkg_name_safe + "/"); } @@ -633,62 +691,31 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p print_line("ADDING: " + file + " size: " + itos(data.size())); total_size += data.size(); - if (export_format == "dmg") { - // write it into our application bundle - file = tmp_app_path_name.plus_file(file); - if (err == OK) { - err = tmp_app_path->make_dir_recursive(file.get_base_dir()); - } - if (err == OK) { - // write the file, need to add chmod - 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; + // Write it into our application bundle. + file = tmp_app_path_name.plus_file(file); + if (err == OK) { + err = tmp_app_path->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; } - } else { - // add it to our zip file - file = pkg_name + ".app/" + file; - - zip_fileinfo fi; - fi.tmz_date.tm_hour = info.tmu_date.tm_hour; - fi.tmz_date.tm_min = info.tmu_date.tm_min; - fi.tmz_date.tm_sec = info.tmu_date.tm_sec; - fi.tmz_date.tm_mon = info.tmu_date.tm_mon; - fi.tmz_date.tm_mday = info.tmu_date.tm_mday; - fi.tmz_date.tm_year = info.tmu_date.tm_year; - fi.dosDate = info.dosDate; - fi.internal_fa = info.internal_fa; - fi.external_fa = info.external_fa; - - zipOpenNewFileInZip(dst_pkg_zip, - file.utf8().get_data(), - &fi, - nullptr, - 0, - nullptr, - 0, - nullptr, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - - zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); - zipCloseFileInZip(dst_pkg_zip); } } ret = unzGoToNextFile(src_pkg_zip); } - // we're done with our source zip + // We're done with our source zip. unzClose(src_pkg_zip); if (!found_binary) { @@ -701,124 +728,143 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p return ERR_SKIP; } - if (export_format == "dmg") { - 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); + 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"); + // See if we can code sign our new package. + bool sign_enabled = p_preset->get("codesign/enable"); - if (err == OK) { - DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - for (int i = 0; i < shared_objects.size(); i++) { - err = da->copy(shared_objects[i].path, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file()); - if (err == OK && sign_enabled) { - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file()); - } + if (err == OK) { + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + for (int i = 0; i < shared_objects.size(); i++) { + err = da->copy(shared_objects[i].path, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file()); + if (err == OK && sign_enabled) { + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file()); } - memdelete(da); } + memdelete(da); + } - if (err == OK && sign_enabled) { - if (ep.step("Code signing bundle", 2)) { - return ERR_SKIP; - } - - // the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP - - // start with our application - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name); - - ///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign + 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); + } - // and finally create a DMG + 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); } - - // Clean up temporary .app dir - OS::get_singleton()->move_to_trash(tmp_app_path_name); - - } else { // pck - - String pack_path = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".pck"); - - Vector<SharedObject> shared_objects; - err = save_pack(p_preset, pack_path, &shared_objects); - - if (err == OK) { - zipOpenNewFileInZip(dst_pkg_zip, - (pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(), - nullptr, - nullptr, - 0, - nullptr, - 0, - nullptr, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - - FileAccess *pf = FileAccess::open(pack_path, FileAccess::READ); - if (pf) { - const int BSIZE = 16384; - uint8_t buf[BSIZE]; - - while (true) { - - int r = pf->get_buffer(buf, BSIZE); - if (r <= 0) - break; - zipWriteInFileInZip(dst_pkg_zip, buf, r); - } - - zipCloseFileInZip(dst_pkg_zip); - memdelete(pf); - } else { - err = ERR_CANT_OPEN; + // Sign DMG. + if (err == OK && sign_enabled) { + if (ep.step("Code signing DMG", 3)) { + return ERR_SKIP; } + err = _code_sign(p_preset, p_path); } - + } else { + // Create ZIP. if (err == OK) { - //add shared objects - for (int i = 0; i < shared_objects.size(); i++) { - Vector<uint8_t> file = FileAccess::get_file_as_array(shared_objects[i].path); - ERR_CONTINUE(file.empty()); - - zipOpenNewFileInZip(dst_pkg_zip, - (pkg_name + ".app/Contents/Frameworks/").plus_file(shared_objects[i].path.get_file()).utf8().get_data(), - nullptr, - nullptr, - 0, - nullptr, - 0, - nullptr, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - - zipWriteInFileInZip(dst_pkg_zip, file.ptr(), file.size()); - zipCloseFileInZip(dst_pkg_zip); + 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, EditorSettings::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name); + + zipClose(zip, nullptr); } + } - // Clean up generated file. - DirAccess::remove_file_or_error(pack_path); + 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); } - } - if (dst_pkg_zip) { - zipClose(dst_pkg_zip, nullptr); + // Clean up temporary .app dir. + OS::get_singleton()->move_to_trash(tmp_app_path_name); } return err; } -bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { +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); + + DirAccess *da = DirAccess::open(dir); + da->list_dir_begin(); + String f; + while ((f = da->get_next()) != "") { + if (f == "." || f == "..") { + continue; + } + 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)); + + 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.min; + zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/ + zipfi.tmz_date.tm_sec = time.sec; + 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); + + Vector<uint8_t> array = FileAccess::get_file_as_array(dir.plus_file(f)); + zipWriteInFileInZip(p_zip, array.ptr(), array.size()); + zipCloseFileInZip(p_zip); + } + } + da->list_dir_end(); + memdelete(da); +} +bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; @@ -843,13 +889,48 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset valid = dvalid || rvalid; r_missing_templates = !valid; - if (!err.empty()) + 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"); + if (sign_enabled) { + if (p_preset->get("codesign/identity") == "") { + err += TTR("Codesign: identity not specified.") + "\n"; + valid = false; + } + } + 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.empty()) { r_error = err; + } return valid; } EditorExportPlatformOSX::EditorExportPlatformOSX() { - Ref<Image> img = memnew(Image(_osx_logo)); logo.instance(); logo->create_from_image(img); @@ -859,7 +940,6 @@ EditorExportPlatformOSX::~EditorExportPlatformOSX() { } void register_osx_exporter() { - Ref<EditorExportPlatformOSX> platform; platform.instance(); diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm index eacd2b5cc6..4e73d5441c 100644 --- a/platform/osx/godot_main_osx.mm +++ b/platform/osx/godot_main_osx.mm @@ -36,9 +36,8 @@ #include <unistd.h> int main(int argc, char **argv) { - #if defined(VULKAN_ENABLED) - //MoltenVK - enable full component swizzling support + // MoltenVK - enable full component swizzling support setenv("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1); #endif @@ -61,6 +60,9 @@ int main(int argc, char **argv) { 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()); diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp index 643acd8944..cfc371710b 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/osx/joypad_osx.cpp @@ -98,6 +98,7 @@ int joypad::get_hid_element_state(rec_element *p_element) const { } return value; } + void joypad::add_hid_element(IOHIDElementRef p_element) { const CFTypeID elementTypeID = p_element ? CFGetTypeID(p_element) : 0; @@ -240,7 +241,6 @@ static bool is_joypad(IOHIDDeviceRef p_device_ref) { } void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { - if (p_res != kIOReturnSuccess || have_device(p_device)) { return; } @@ -264,7 +264,6 @@ void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { } void JoypadOSX::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) { - int device = get_joy_ref(p_device); ERR_FAIL_COND(device == -1); @@ -274,7 +273,6 @@ void JoypadOSX::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) { } static String _hex_str(uint8_t p_byte) { - static const char *dict = "0123456789abcdef"; char ret[3]; ret[2] = 0; @@ -286,7 +284,6 @@ static String _hex_str(uint8_t p_byte) { } bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { - p_joy->device_ref = p_device_ref; /* get device name */ String name; @@ -314,9 +311,16 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { 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, "%04x%08x%04x%08x", OSSwapHostToBigInt32(vendor), 0, OSSwapHostToBigInt32(product_id), 0); + 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 @@ -346,7 +350,6 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { } \ } 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); @@ -368,13 +371,13 @@ bool joypad::config_force_feedback(io_service_t p_service) { #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; + 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); @@ -395,38 +398,38 @@ bool joypad::check_ff_features() { static int process_hat_value(int p_min, int p_max, int p_value) { int range = (p_max - p_min + 1); int value = p_value - p_min; - int hat_value = InputFilter::HAT_MASK_CENTER; + int hat_value = Input::HAT_MASK_CENTER; if (range == 4) { value *= 2; } switch (value) { case 0: - hat_value = InputFilter::HAT_MASK_UP; + hat_value = Input::HAT_MASK_UP; break; case 1: - hat_value = InputFilter::HAT_MASK_UP | InputFilter::HAT_MASK_RIGHT; + hat_value = Input::HAT_MASK_UP | Input::HAT_MASK_RIGHT; break; case 2: - hat_value = InputFilter::HAT_MASK_RIGHT; + hat_value = Input::HAT_MASK_RIGHT; break; case 3: - hat_value = InputFilter::HAT_MASK_DOWN | InputFilter::HAT_MASK_RIGHT; + hat_value = Input::HAT_MASK_DOWN | Input::HAT_MASK_RIGHT; break; case 4: - hat_value = InputFilter::HAT_MASK_DOWN; + hat_value = Input::HAT_MASK_DOWN; break; case 5: - hat_value = InputFilter::HAT_MASK_DOWN | InputFilter::HAT_MASK_LEFT; + hat_value = Input::HAT_MASK_DOWN | Input::HAT_MASK_LEFT; break; case 6: - hat_value = InputFilter::HAT_MASK_LEFT; + hat_value = Input::HAT_MASK_LEFT; break; case 7: - hat_value = InputFilter::HAT_MASK_UP | InputFilter::HAT_MASK_LEFT; + hat_value = Input::HAT_MASK_UP | Input::HAT_MASK_LEFT; break; default: - hat_value = InputFilter::HAT_MASK_CENTER; + hat_value = Input::HAT_MASK_CENTER; break; } return hat_value; @@ -438,8 +441,8 @@ void JoypadOSX::poll_joypads() const { } } -static const InputFilter::JoyAxis axis_correct(int p_value, int p_min, int p_max) { - InputFilter::JoyAxis jx; +static const Input::JoyAxis axis_correct(int p_value, int p_min, int p_max) { + Input::JoyAxis jx; if (p_min < 0) { jx.min = -1; if (p_value < 0) { @@ -509,14 +512,16 @@ void JoypadOSX::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { 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; + 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; + if (device_list[i].device_ref == p_device) + return i; } return -1; } @@ -556,7 +561,6 @@ static CFDictionaryRef create_match_dictionary(const UInt32 page, const UInt32 u } void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const { - CFRunLoopRef runloop = CFRunLoopGetCurrent(); IOReturn ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); ERR_FAIL_COND(ret != kIOReturnSuccess); @@ -571,7 +575,7 @@ void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const { } } -JoypadOSX::JoypadOSX(InputFilter *in) { +JoypadOSX::JoypadOSX(Input *in) { self = this; input = in; @@ -600,7 +604,6 @@ JoypadOSX::JoypadOSX(InputFilter *in) { } JoypadOSX::~JoypadOSX() { - for (int i = 0; i < device_list.size(); i++) { device_list.write[i].free(); } diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h index 62027c6a30..dc238e68e4 100644 --- a/platform/osx/joypad_osx.h +++ b/platform/osx/joypad_osx.h @@ -40,7 +40,7 @@ #include <ForceFeedback/ForceFeedbackConstants.h> #include <IOKit/hid/IOHIDLib.h> -#include "core/input/input_filter.h" +#include "core/input/input.h" struct rec_element { IOHIDElementRef ref; @@ -88,13 +88,12 @@ struct joypad { }; class JoypadOSX { - enum { JOYPADS_MAX = 16, }; private: - InputFilter *input; + Input *input; IOHIDManagerRef hid_manager; Vector<joypad> device_list; @@ -118,7 +117,7 @@ public: void _device_added(IOReturn p_res, IOHIDDeviceRef p_device); void _device_removed(IOReturn p_res, IOHIDDeviceRef p_device); - JoypadOSX(InputFilter *in); + JoypadOSX(Input *in); ~JoypadOSX(); }; diff --git a/platform/osx/logo.png b/platform/osx/logo.png Binary files differindex 834bbf3ba6..b5a660b165 100644 --- a/platform/osx/logo.png +++ b/platform/osx/logo.png diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index d2c67cff9f..9204a145bf 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -31,7 +31,7 @@ #ifndef OS_OSX_H #define OS_OSX_H -#include "core/input/input_filter.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" diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 49cb056c9f..c4eb5407af 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -60,39 +60,31 @@ public: switch (p_type) { case ERR_WARNING: - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_12) { - os_log_info(OS_LOG_DEFAULT, - "WARNING: %{public}s\nat: %{public}s (%{public}s:%i)", - err_details, p_function, p_file, p_line); - } + 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: - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_12) { - os_log_error(OS_LOG_DEFAULT, - "SCRIPT ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", - err_details, p_function, p_file, p_line); - } + 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: - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_12) { - os_log_error(OS_LOG_DEFAULT, - "SHADER ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", - err_details, p_function, p_file, p_line); - } + 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: - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_12) { - os_log_error(OS_LOG_DEFAULT, - "ERROR: %{public}s\nat: %{public}s (%{public}s:%i)", - err_details, p_function, p_file, p_line); - } + 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; @@ -136,7 +128,7 @@ void OS_OSX::initialize_core() { } void OS_OSX::initialize_joypads() { - joypad_osx = memnew(JoypadOSX(InputFilter::get_singleton())); + joypad_osx = memnew(JoypadOSX(Input::get_singleton())); } void OS_OSX::initialize() { @@ -147,7 +139,6 @@ void OS_OSX::initialize() { } void OS_OSX::finalize() { - #ifdef COREMIDI_ENABLED midi_driver.close(); #endif @@ -269,10 +260,8 @@ String OS_OSX::get_system_dir(SystemDir p_dir) const { 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); @@ -283,7 +272,13 @@ String OS_OSX::get_system_dir(SystemDir p_dir) const { } Error OS_OSX::shell_open(String p_uri) { - [[NSWorkspace sharedWorkspace] openURL:[[NSURL alloc] initWithString:[[NSString stringWithUTF8String:p_uri.utf8().get_data()] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]]; + 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; } @@ -325,7 +320,7 @@ void OS_OSX::run() { } joypad_osx->process_joypads(); - if (Main::iteration() == true) { + if (Main::iteration()) { quit = true; } } @catch (NSException *exception) { diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h index 155f37ed55..e657aca955 100644 --- a/platform/osx/platform_config.h +++ b/platform/osx/platform_config.h @@ -30,5 +30,4 @@ #include <alloca.h> -#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h" #define PTHREAD_RENAME_SELF diff --git a/platform/osx/vulkan_context_osx.h b/platform/osx/vulkan_context_osx.h index 09a5494ae8..e996f176a9 100644 --- a/platform/osx/vulkan_context_osx.h +++ b/platform/osx/vulkan_context_osx.h @@ -35,7 +35,6 @@ #include <AppKit/AppKit.h> class VulkanContextOSX : public VulkanContext { - virtual const char *_get_platform_surface_extension() const; public: diff --git a/platform/osx/vulkan_context_osx.mm b/platform/osx/vulkan_context_osx.mm index 320401cdcb..ec8745ff01 100644 --- a/platform/osx/vulkan_context_osx.mm +++ b/platform/osx/vulkan_context_osx.mm @@ -36,7 +36,6 @@ const char *VulkanContextOSX::_get_platform_surface_extension() const { } Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, id p_window, int p_width, int p_height) { - VkMacOSSurfaceCreateInfoMVK createInfo; createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = NULL; |