From 238ac2fdd5e9d93f51a32d9341c5b70eb66bb491 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Thu, 7 Jul 2022 10:57:22 +0300 Subject: [macOS] Improve file association handling, and allow URL schema handling. --- core/os/os.h | 1 + main/main.cpp | 7 ++++ platform/osx/godot_application_delegate.h | 1 + platform/osx/godot_application_delegate.mm | 65 +++++++++++++++++++++--------- platform/osx/godot_main_osx.mm | 9 +---- platform/osx/os_osx.h | 6 +-- platform/osx/os_osx.mm | 8 ++-- 7 files changed, 63 insertions(+), 34 deletions(-) diff --git a/core/os/os.h b/core/os/os.h index af6c38cbe0..0428f6df2a 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -160,6 +160,7 @@ public: virtual String get_name() const = 0; virtual List get_cmdline_args() const { return _cmdline; } + virtual List get_cmdline_platform_args() const { return List(); } virtual String get_model_name() const; bool is_layered_allowed() const { return _allow_layered; } diff --git a/main/main.cpp b/main/main.cpp index f7c192001b..eb401cd9ef 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -621,11 +621,18 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph /* argument parsing and main creation */ List args; List main_args; + List platform_args = OS::get_singleton()->get_cmdline_platform_args(); + // Add command line arguments. for (int i = 0; i < argc; i++) { args.push_back(String::utf8(argv[i])); } + // Add arguments received from macOS LaunchService (URL schemas, file associations). + for (const String &arg : platform_args) { + args.push_back(arg); + } + List::Element *I = args.front(); while (I) { diff --git a/platform/osx/godot_application_delegate.h b/platform/osx/godot_application_delegate.h index 8eec762d8f..f5b67b580f 100644 --- a/platform/osx/godot_application_delegate.h +++ b/platform/osx/godot_application_delegate.h @@ -40,6 +40,7 @@ - (void)forceUnbundledWindowActivationHackStep1; - (void)forceUnbundledWindowActivationHackStep2; - (void)forceUnbundledWindowActivationHackStep3; +- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; @end #endif // GODOT_APPLICATION_DELEGATE_H diff --git a/platform/osx/godot_application_delegate.mm b/platform/osx/godot_application_delegate.mm index dc82075c44..4d3558b273 100644 --- a/platform/osx/godot_application_delegate.mm +++ b/platform/osx/godot_application_delegate.mm @@ -67,6 +67,52 @@ } } +- (id)init { + self = [super init]; + + NSAppleEventManager *aem = [NSAppleEventManager sharedAppleEventManager]; + [aem setEventHandler:self andSelector:@selector(handleAppleEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; + [aem setEventHandler:self andSelector:@selector(handleAppleEvent:withReplyEvent:) forEventClass:kCoreEventClass andEventID:kAEOpenDocuments]; + + return self; +} + +- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { + OS_OSX *os = (OS_OSX *)OS::get_singleton(); + if (!event || !os) { + return; + } + + List args; + if (([event eventClass] == kInternetEventClass) && ([event eventID] == kAEGetURL)) { + // Opening URL scheme. + NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + args.push_back(vformat("--uri=\"%s\"", String::utf8([url UTF8String]))); + } + + if (([event eventClass] == kCoreEventClass) && ([event eventID] == kAEOpenDocuments)) { + // Opening file association. + NSAppleEventDescriptor *files = [event paramDescriptorForKeyword:keyDirectObject]; + if (files) { + NSInteger count = [files numberOfItems]; + for (NSInteger i = 1; i <= count; i++) { + NSURL *url = [NSURL URLWithString:[[files descriptorAtIndex:i] stringValue]]; + args.push_back(String::utf8([url.path UTF8String])); + } + } + } + + if (!args.is_empty()) { + if (os->get_main_loop()) { + // Application is already running, open a new instance with the URL/files as command line arguments. + os->create_instance(args); + } else { + // Application is just started, add to the list of command line arguments and continue. + os->set_cmdline_platform_args(args); + } + } +} + - (void)applicationDidResignActive:(NSNotification *)notification { DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); if (ds) { @@ -99,25 +145,6 @@ } } -- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename { - // Note: may be called called before main loop init! - OS_OSX *os = (OS_OSX *)OS::get_singleton(); - if (os) { - os->set_open_with_filename(String::utf8([filename UTF8String])); - } - -#ifdef TOOLS_ENABLED - // Open new instance. - if (os && os->get_main_loop()) { - List args; - args.push_back(os->get_open_with_filename()); - String exec = os->get_executable_path(); - os->create_process(exec, args); - } -#endif - return YES; -} - - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); if (ds) { diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm index 354edca096..722928ad60 100644 --- a/platform/osx/godot_main_osx.mm +++ b/platform/osx/godot_main_osx.mm @@ -74,14 +74,7 @@ int main(int argc, char **argv) { // We must override main when testing is enabled. TEST_MAIN_OVERRIDE - if (os.get_open_with_filename() != "") { - char *argv_c = (char *)malloc(os.get_open_with_filename().utf8().size()); - memcpy(argv_c, os.get_open_with_filename().utf8().get_data(), os.get_open_with_filename().utf8().size()); - err = Main::setup(argv[0], 1, &argv_c); - free(argv_c); - } else { - err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]); - } + err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]); if (err == ERR_HELP) { // Returned by --help and --version, so success. return 0; diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index e4ec411c96..b105be4a06 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -57,7 +57,7 @@ class OS_OSX : public OS_Unix { MainLoop *main_loop = nullptr; - String open_with_filename; + List launch_service_args; static _FORCE_INLINE_ String get_framework_executable(const String &p_path); static void pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context); @@ -73,8 +73,8 @@ protected: virtual void delete_main_loop() override; public: - String get_open_with_filename() const; - void set_open_with_filename(const String &p_path); + virtual void set_cmdline_platform_args(const List &p_args); + virtual List get_cmdline_platform_args() const override; virtual String get_name() const override; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index a8fa56e34b..5230ed4155 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -121,12 +121,12 @@ void OS_OSX::delete_main_loop() { main_loop = nullptr; } -String OS_OSX::get_open_with_filename() const { - return open_with_filename; +void OS_OSX::set_cmdline_platform_args(const List &p_args) { + launch_service_args = p_args; } -void OS_OSX::set_open_with_filename(const String &p_path) { - open_with_filename = p_path; +List OS_OSX::get_cmdline_platform_args() const { + return launch_service_args; } String OS_OSX::get_name() const { -- cgit v1.2.3