diff --git a/modules/juce_events/native/juce_mac_MessageManager.mm b/modules/juce_events/native/juce_mac_MessageManager.mm index 245bed7601..592890fe06 100644 --- a/modules/juce_events/native/juce_mac_MessageManager.mm +++ b/modules/juce_events/native/juce_mac_MessageManager.mm @@ -35,151 +35,186 @@ MenuTrackingChangedCallback menuTrackingChangedCallback = nullptr; //============================================================================== struct AppDelegateClass : public ObjCClass { - AppDelegateClass() : ObjCClass ("JUCEAppDelegate_") + AppDelegateClass() : ObjCClass ("JUCEAppDelegate_") { - addMethod (@selector (applicationWillFinishLaunching:), applicationWillFinishLaunching); - addMethod (@selector (applicationShouldTerminate:), applicationShouldTerminate); - addMethod (@selector (applicationWillTerminate:), applicationWillTerminate); - addMethod (@selector (application:openFile:), application_openFile); - addMethod (@selector (application:openFiles:), application_openFiles); - addMethod (@selector (applicationDidBecomeActive:), applicationDidBecomeActive); - addMethod (@selector (applicationDidResignActive:), applicationDidResignActive); - addMethod (@selector (applicationWillUnhide:), applicationWillUnhide); + addMethod (@selector (applicationWillFinishLaunching:), [] (id self, SEL, NSNotification*) + { + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") + [[NSAppleEventManager sharedAppleEventManager] setEventHandler: self + andSelector: @selector (getUrl:withReplyEvent:) + forEventClass: kInternetEventClass + andEventID: kAEGetURL]; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + }); + + addMethod (@selector (applicationShouldTerminate:), [] (id /*self*/, SEL, NSApplication*) + { + if (auto* app = JUCEApplicationBase::getInstance()) + { + app->systemRequestedQuit(); + + if (! MessageManager::getInstance()->hasStopMessageBeenSent()) + return NSTerminateCancel; + } + + return NSTerminateNow; + }); + + addMethod (@selector (applicationWillTerminate:), [] (id /*self*/, SEL, NSNotification*) + { + JUCEApplicationBase::appWillTerminateByForce(); + }); + + addMethod (@selector (application:openFile:), [] (id /*self*/, SEL, NSApplication*, NSString* filename) + { + if (auto* app = JUCEApplicationBase::getInstance()) + { + app->anotherInstanceStarted (quotedIfContainsSpaces (filename)); + return YES; + } + + return NO; + }); + + addMethod (@selector (application:openFiles:), [] (id /*self*/, SEL, NSApplication*, NSArray* filenames) + { + if (auto* app = JUCEApplicationBase::getInstance()) + { + StringArray files; + + for (NSString* f in filenames) + files.add (quotedIfContainsSpaces (f)); + + if (files.size() > 0) + app->anotherInstanceStarted (files.joinIntoString (" ")); + } + }); + + addMethod (@selector (applicationDidBecomeActive:), [] (id /*self*/, SEL, NSNotification*) { focusChanged(); }); + addMethod (@selector (applicationDidResignActive:), [] (id /*self*/, SEL, NSNotification*) { focusChanged(); }); + addMethod (@selector (applicationWillUnhide:), [] (id /*self*/, SEL, NSNotification*) { focusChanged(); }); JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - addMethod (@selector (getUrl:withReplyEvent:), getUrl_withReplyEvent); - addMethod (@selector (broadcastMessageCallback:), broadcastMessageCallback); - addMethod (@selector (mainMenuTrackingBegan:), mainMenuTrackingBegan); - addMethod (@selector (mainMenuTrackingEnded:), mainMenuTrackingEnded); - addMethod (@selector (dummyMethod), dummyMethod); + addMethod (@selector (getUrl:withReplyEvent:), [] (id /*self*/, SEL, NSAppleEventDescriptor* event, NSAppleEventDescriptor*) + { + if (auto* app = JUCEApplicationBase::getInstance()) + app->anotherInstanceStarted (quotedIfContainsSpaces ([[event paramDescriptorForKeyword: keyDirectObject] stringValue])); + }); + + addMethod (@selector (broadcastMessageCallback:), [] (id /*self*/, SEL, NSNotification* n) + { + NSDictionary* dict = (NSDictionary*) [n userInfo]; + auto messageString = nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")]); + MessageManager::getInstance()->deliverBroadcastMessage (messageString); + }); + + addMethod (@selector (mainMenuTrackingBegan:), [] (id /*self*/, SEL, NSNotification*) + { + if (menuTrackingChangedCallback != nullptr) + menuTrackingChangedCallback (true); + }); + + addMethod (@selector (mainMenuTrackingEnded:), [] (id /*self*/, SEL, NSNotification*) + { + if (menuTrackingChangedCallback != nullptr) + menuTrackingChangedCallback (false); + }); + + // (used as a way of running a dummy thread) + addMethod (@selector (dummyMethod), [] (id /*self*/, SEL) {}); JUCE_END_IGNORE_WARNINGS_GCC_LIKE #if JUCE_PUSH_NOTIFICATIONS //============================================================================== addIvar*> ("pushNotificationsDelegate"); - addMethod (@selector (applicationDidFinishLaunching:), applicationDidFinishLaunching); + addMethod (@selector (applicationDidFinishLaunching:), [] (id self, SEL, NSNotification* notification) + { + if (notification.userInfo != nil) + { + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + // NSUserNotification is deprecated from macOS 11, but there doesn't seem to be a + // replacement for NSApplicationLaunchUserNotificationKey returning a non-deprecated type + NSUserNotification* userNotification = notification.userInfo[NSApplicationLaunchUserNotificationKey]; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + if (userNotification != nil && userNotification.userInfo != nil) + didReceiveRemoteNotification (self, nil, [NSApplication sharedApplication], userNotification.userInfo); + } + }); JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - addMethod (@selector (setPushNotificationsDelegate:), setPushNotificationsDelegate); + addMethod (@selector (setPushNotificationsDelegate:), [] (id self, SEL, NSObject* delegate) + { + object_setInstanceVariable (self, "pushNotificationsDelegate", delegate); + }); JUCE_END_IGNORE_WARNINGS_GCC_LIKE - addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), registeredForRemoteNotifications); - addMethod (@selector (application:didFailToRegisterForRemoteNotificationsWithError:), failedToRegisterForRemoteNotifications); - addMethod (@selector (application:didReceiveRemoteNotification:), didReceiveRemoteNotification); + addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), [] (id self, SEL, NSApplication* application, NSData* deviceToken) + { + auto* delegate = getPushNotificationsDelegate (self); + + SEL selector = @selector (application:didRegisterForRemoteNotificationsWithDeviceToken:); + + if (delegate != nil && [delegate respondsToSelector: selector]) + { + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; + [invocation setSelector: selector]; + [invocation setTarget: delegate]; + [invocation setArgument: &application atIndex:2]; + [invocation setArgument: &deviceToken atIndex:3]; + + [invocation invoke]; + } + }); + + addMethod (@selector (application:didFailToRegisterForRemoteNotificationsWithError:), [] (id self, SEL, NSApplication* application, NSError* error) + { + auto* delegate = getPushNotificationsDelegate (self); + + SEL selector = @selector (application:didFailToRegisterForRemoteNotificationsWithError:); + + if (delegate != nil && [delegate respondsToSelector: selector]) + { + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; + [invocation setSelector: selector]; + [invocation setTarget: delegate]; + [invocation setArgument: &application atIndex:2]; + [invocation setArgument: &error atIndex:3]; + + [invocation invoke]; + } + }); + + addMethod (@selector (application:didReceiveRemoteNotification:), [] (id self, SEL, NSApplication* application, NSDictionary* userInfo) + { + auto* delegate = getPushNotificationsDelegate (self); + + SEL selector = @selector (application:didReceiveRemoteNotification:); + + if (delegate != nil && [delegate respondsToSelector: selector]) + { + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; + [invocation setSelector: selector]; + [invocation setTarget: delegate]; + [invocation setArgument: &application atIndex:2]; + [invocation setArgument: &userInfo atIndex:3]; + + [invocation invoke]; + } + }); #endif registerClass(); } private: - static void applicationWillFinishLaunching (id self, SEL, NSNotification*) - { - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - [[NSAppleEventManager sharedAppleEventManager] setEventHandler: self - andSelector: @selector (getUrl:withReplyEvent:) - forEventClass: kInternetEventClass - andEventID: kAEGetURL]; - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - } - - #if JUCE_PUSH_NOTIFICATIONS - static void applicationDidFinishLaunching (id self, SEL, NSNotification* notification) - { - if (notification.userInfo != nil) - { - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") - // NSUserNotification is deprecated from macOS 11, but there doesn't seem to be a - // replacement for NSApplicationLaunchUserNotificationKey returning a non-deprecated type - NSUserNotification* userNotification = notification.userInfo[NSApplicationLaunchUserNotificationKey]; - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - - if (userNotification != nil && userNotification.userInfo != nil) - didReceiveRemoteNotification (self, nil, [NSApplication sharedApplication], userNotification.userInfo); - } - } - #endif - - static NSApplicationTerminateReply applicationShouldTerminate (id /*self*/, SEL, NSApplication*) - { - if (auto* app = JUCEApplicationBase::getInstance()) - { - app->systemRequestedQuit(); - - if (! MessageManager::getInstance()->hasStopMessageBeenSent()) - return NSTerminateCancel; - } - - return NSTerminateNow; - } - - static void applicationWillTerminate (id /*self*/, SEL, NSNotification*) - { - JUCEApplicationBase::appWillTerminateByForce(); - } - - static BOOL application_openFile (id /*self*/, SEL, NSApplication*, NSString* filename) - { - if (auto* app = JUCEApplicationBase::getInstance()) - { - app->anotherInstanceStarted (quotedIfContainsSpaces (filename)); - return YES; - } - - return NO; - } - - static void application_openFiles (id /*self*/, SEL, NSApplication*, NSArray* filenames) - { - if (auto* app = JUCEApplicationBase::getInstance()) - { - StringArray files; - - for (NSString* f in filenames) - files.add (quotedIfContainsSpaces (f)); - - if (files.size() > 0) - app->anotherInstanceStarted (files.joinIntoString (" ")); - } - } - - static void applicationDidBecomeActive (id /*self*/, SEL, NSNotification*) { focusChanged(); } - static void applicationDidResignActive (id /*self*/, SEL, NSNotification*) { focusChanged(); } - static void applicationWillUnhide (id /*self*/, SEL, NSNotification*) { focusChanged(); } - - static void broadcastMessageCallback (id /*self*/, SEL, NSNotification* n) - { - NSDictionary* dict = (NSDictionary*) [n userInfo]; - auto messageString = nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")]); - MessageManager::getInstance()->deliverBroadcastMessage (messageString); - } - - static void mainMenuTrackingBegan (id /*self*/, SEL, NSNotification*) - { - if (menuTrackingChangedCallback != nullptr) - menuTrackingChangedCallback (true); - } - - static void mainMenuTrackingEnded (id /*self*/, SEL, NSNotification*) - { - if (menuTrackingChangedCallback != nullptr) - menuTrackingChangedCallback (false); - } - - static void dummyMethod (id /*self*/, SEL) {} // (used as a way of running a dummy thread) - static void focusChanged() { if (appFocusChangeCallback != nullptr) (*appFocusChangeCallback)(); } - static void getUrl_withReplyEvent (id /*self*/, SEL, NSAppleEventDescriptor* event, NSAppleEventDescriptor*) - { - if (auto* app = JUCEApplicationBase::getInstance()) - app->anotherInstanceStarted (quotedIfContainsSpaces ([[event paramDescriptorForKeyword: keyDirectObject] stringValue])); - } - static String quotedIfContainsSpaces (NSString* file) { String s (nsStringToJuce (file)); @@ -191,71 +226,12 @@ private: return s; } - #if JUCE_PUSH_NOTIFICATIONS //============================================================================== - static void setPushNotificationsDelegate (id self, SEL, NSObject* delegate) - { - object_setInstanceVariable (self, "pushNotificationsDelegate", delegate); - } - + #if JUCE_PUSH_NOTIFICATIONS static NSObject* getPushNotificationsDelegate (id self) { return getIvar*> (self, "pushNotificationsDelegate"); } - - static void registeredForRemoteNotifications (id self, SEL, NSApplication* application, NSData* deviceToken) - { - auto* delegate = getPushNotificationsDelegate (self); - - SEL selector = @selector (application:didRegisterForRemoteNotificationsWithDeviceToken:); - - if (delegate != nil && [delegate respondsToSelector: selector]) - { - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; - [invocation setSelector: selector]; - [invocation setTarget: delegate]; - [invocation setArgument: &application atIndex:2]; - [invocation setArgument: &deviceToken atIndex:3]; - - [invocation invoke]; - } - } - - static void failedToRegisterForRemoteNotifications (id self, SEL, NSApplication* application, NSError* error) - { - auto* delegate = getPushNotificationsDelegate (self); - - SEL selector = @selector (application:didFailToRegisterForRemoteNotificationsWithError:); - - if (delegate != nil && [delegate respondsToSelector: selector]) - { - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; - [invocation setSelector: selector]; - [invocation setTarget: delegate]; - [invocation setArgument: &application atIndex:2]; - [invocation setArgument: &error atIndex:3]; - - [invocation invoke]; - } - } - - static void didReceiveRemoteNotification (id self, SEL, NSApplication* application, NSDictionary* userInfo) - { - auto* delegate = getPushNotificationsDelegate (self); - - SEL selector = @selector (application:didReceiveRemoteNotification:); - - if (delegate != nil && [delegate respondsToSelector: selector]) - { - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; - [invocation setSelector: selector]; - [invocation setTarget: delegate]; - [invocation setArgument: &application atIndex:2]; - [invocation setArgument: &userInfo atIndex:3]; - - [invocation invoke]; - } - } #endif };