diff --git a/extras/Introjucer/Source/Project/jucer_AudioPluginModule.h b/extras/Introjucer/Source/Project/jucer_AudioPluginModule.h index a3d4c1fd5c..cc6215038b 100644 --- a/extras/Introjucer/Source/Project/jucer_AudioPluginModule.h +++ b/extras/Introjucer/Source/Project/jucer_AudioPluginModule.h @@ -474,12 +474,6 @@ namespace AAXHelpers static bool isExporterSupported (ProjectExporter& exporter) { return exporter.isVisualStudio() || exporter.isXcode(); } - static RelativePath getAAXFolderRelativePath (ProjectExporter& exporter) - { - return exporter.rebaseFromProjectFolderToBuildTarget (RelativePath (getAAXFolder (exporter).toString(), - RelativePath::projectFolder)); - } - static void fixMissingAAXValues (ProjectExporter& exporter) { if (getAAXFolder (exporter).toString().isEmpty()) diff --git a/modules/juce_core/native/juce_BasicNativeHeaders.h b/modules/juce_core/native/juce_BasicNativeHeaders.h index 1f23a7d37f..43451bbde7 100644 --- a/modules/juce_core/native/juce_BasicNativeHeaders.h +++ b/modules/juce_core/native/juce_BasicNativeHeaders.h @@ -62,6 +62,9 @@ #include #include #include + #include + #include + #include //============================================================================== #elif JUCE_WINDOWS diff --git a/modules/juce_core/native/juce_osx_ObjCHelpers.h b/modules/juce_core/native/juce_osx_ObjCHelpers.h index ea339cb8c5..59f8248430 100644 --- a/modules/juce_core/native/juce_osx_ObjCHelpers.h +++ b/modules/juce_core/native/juce_osx_ObjCHelpers.h @@ -54,5 +54,50 @@ namespace } } +//============================================================================== +class ObjCClassBuilder +{ +public: + ObjCClassBuilder (Class superClass, const String& name) + : cls (objc_allocateClassPair (superClass, name.toUTF8(), 0)) + { + } + + Class getClass() + { + objc_registerClassPair (cls); + return cls; + } + + template + void addIvar (const char* name) + { + BOOL b = class_addIvar (cls, name, sizeof (Type), (uint8_t) rint (log2 (sizeof (Type))), @encode (Type)); + jassert (b); (void) b; + } + + template + void addMethod (SEL selector, FunctionType callbackFn, const char* signature) + { + BOOL b = class_addMethod (cls, selector, (IMP) callbackFn, signature); + jassert (b); (void) b; + } + + static id sendSuperclassMessage (id self, SEL selector) + { + objc_super s = { self, [NSObject class] }; + return objc_msgSendSuper (&s, selector); + } + + static String getRandomisedName (const char* root) + { + return root + String::toHexString (Random::getSystemRandom().nextInt64()); + } + +private: + Class cls; + + JUCE_DECLARE_NON_COPYABLE (ObjCClassBuilder); +}; #endif // __JUCE_OSX_OBJCHELPERS_JUCEHEADER__ diff --git a/modules/juce_events/native/juce_mac_MessageManager.mm b/modules/juce_events/native/juce_mac_MessageManager.mm index 92219c0ac1..477f8baf6b 100644 --- a/modules/juce_events/native/juce_mac_MessageManager.mm +++ b/modules/juce_events/native/juce_mac_MessageManager.mm @@ -30,23 +30,92 @@ typedef bool (*CheckEventBlockedByModalComps) (NSEvent*); CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr; //============================================================================== -/* When you use multiple DLLs which share similarly-named obj-c classes - like - for example having more than one juce plugin loaded into a host, then when a - method is called, the actual code that runs might actually be in a different module - than the one you expect... So any calls to library functions or statics that are - made inside obj-c methods will probably end up getting executed in a different DLL's - memory space. Not a great thing to happen - this obviously leads to bizarre crashes. - - To work around this insanity, I'm only allowing obj-c methods to make calls to - virtual methods of an object that's known to live inside the right module's space. -*/ -class AppDelegateRedirector +struct AppDelegateClass { -public: - AppDelegateRedirector() {} - virtual ~AppDelegateRedirector() {} + static Class createClass() + { + ObjCClassBuilder c ([NSObject class], ObjCClassBuilder::getRandomisedName ("JUCEAppDelegate_")); + + c.addMethod (@selector (init), init, "@@:"); + c.addMethod (@selector (dealloc), dealloc, "v@:"); + c.addMethod (@selector (unregisterObservers), unregisterObservers, "v@:"); + c.addMethod (@selector (applicationShouldTerminate:), applicationShouldTerminate, "I@:@"); + c.addMethod (@selector (applicationWillTerminate:), applicationWillTerminate, "v@:@"); + c.addMethod (@selector (application:openFile:), application_openFile, "c@:@@"); + c.addMethod (@selector (application:openFiles:), application_openFiles, "v@:@@"); + c.addMethod (@selector (applicationDidBecomeActive:), applicationDidBecomeActive, "v@:@"); + c.addMethod (@selector (applicationDidResignActive:), applicationDidResignActive, "v@:@"); + c.addMethod (@selector (applicationWillUnhide:), applicationWillUnhide, "v@:@"); + c.addMethod (@selector (broadcastMessageCallback:), broadcastMessageCallback, "v@:@"); + c.addMethod (@selector (dummyMethod), dummyMethod, "v@:"); + + return c.getClass(); + } + + static NSObject* createInstance() + { + static Class c = createClass(); + jassert (c != nullptr); + return class_createInstance (c, 0); + } + + static NSString* getBroacastEventName() + { + return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation (File::currentExecutableFile).hashCode64())); + } + + //============================================================================== + static id init (id self, SEL) + { + self = ObjCClassBuilder::sendSuperclassMessage (self, @selector (init)); + + if (JUCEApplicationBase::isStandaloneApp()) + { + [NSApp setDelegate: self]; + + [[NSDistributedNotificationCenter defaultCenter] addObserver: self + selector: @selector (broadcastMessageCallback:) + name: getBroacastEventName() + object: nil]; + } + else + { + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + + [center addObserver: self selector: @selector (applicationDidResignActive:) + name: NSApplicationDidResignActiveNotification object: NSApp]; + + [center addObserver: self selector: @selector (applicationDidBecomeActive:) + name: NSApplicationDidBecomeActiveNotification object: NSApp]; + + [center addObserver: self selector: @selector (applicationWillUnhide:) + name: NSApplicationWillUnhideNotification object: NSApp]; + } + + return self; + } + + static void dealloc (id self, SEL) + { + ObjCClassBuilder::sendSuperclassMessage (self, @selector (dealloc)); + } + + static void unregisterObservers (id self, SEL) + { + [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: self]; + [[NSNotificationCenter defaultCenter] removeObserver: self]; + + if (JUCEApplicationBase::isStandaloneApp()) + { + [NSApp setDelegate: nil]; - virtual NSApplicationTerminateReply shouldTerminate() + [[NSDistributedNotificationCenter defaultCenter] removeObserver: self + name: getBroacastEventName() + object: nil]; + } + } + + static NSApplicationTerminateReply applicationShouldTerminate (id /*self*/, SEL, NSApplication*) { if (JUCEApplicationBase::getInstance() != nullptr) { @@ -59,12 +128,12 @@ public: return NSTerminateNow; } - virtual void willTerminate() + static void applicationWillTerminate (id /*self*/, SEL, NSNotification*) { JUCEApplicationBase::appWillTerminateByForce(); } - virtual BOOL openFile (NSString* filename) + static BOOL application_openFile (id /*self*/, SEL, NSApplication*, NSString* filename) { if (JUCEApplicationBase::getInstance() != nullptr) { @@ -75,7 +144,7 @@ public: return NO; } - virtual void openFiles (NSArray* filenames) + static void application_openFiles (id /*self*/, SEL, NSApplication*, NSArray* filenames) { StringArray files; for (unsigned int i = 0; i < [filenames count]; ++i) @@ -85,32 +154,26 @@ public: JUCEApplicationBase::getInstance()->anotherInstanceStarted (files.joinIntoString (" ")); } - virtual void focusChanged() - { - if (appFocusChangeCallback != nullptr) - (*appFocusChangeCallback)(); - } + static void applicationDidBecomeActive (id /*self*/, SEL, NSNotification*) { focusChanged(); } + static void applicationDidResignActive (id /*self*/, SEL, NSNotification*) { focusChanged(); } + static void applicationWillUnhide (id /*self*/, SEL, NSNotification*) { focusChanged(); } - virtual void deleteSelf() + static void broadcastMessageCallback (id /*self*/, SEL, NSNotification* n) { - delete this; + NSDictionary* dict = (NSDictionary*) [n userInfo]; + const String messageString (nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")])); + MessageManager::getInstance()->deliverBroadcastMessage (messageString); } - void postMessage (MessageManager::MessageBase* const m) - { - messageQueue.post (m); - } + static void dummyMethod (id /*self*/, SEL) {} // (used as a way of running a dummy thread) - static NSString* getBroacastEventName() +private: + static void focusChanged() { - return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation (File::currentExecutableFile).hashCode64())); + if (appFocusChangeCallback != nullptr) + (*appFocusChangeCallback)(); } -private: - CFRunLoopRef runLoop; - CFRunLoopSourceRef runLoopSource; - MessageQueue messageQueue; - static String quotedIfContainsSpaces (NSString* file) { String s (nsStringToJuce (file)); @@ -121,148 +184,7 @@ private: } }; - -} // (juce namespace) - -using namespace juce; - -#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate) - //============================================================================== -@interface JuceAppDelegate : NSObject -{ -@public - AppDelegateRedirector* redirector; -} - -- (JuceAppDelegate*) init; -- (void) dealloc; -- (void) unregisterObservers; -- (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename; -- (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames; -- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app; -- (void) applicationWillTerminate: (NSNotification*) aNotification; -- (void) applicationDidBecomeActive: (NSNotification*) aNotification; -- (void) applicationDidResignActive: (NSNotification*) aNotification; -- (void) applicationWillUnhide: (NSNotification*) aNotification; -- (void) broadcastMessageCallback: (NSNotification*) info; -- (void) dummyMethod; -@end - -@implementation JuceAppDelegate - -- (JuceAppDelegate*) init -{ - [super init]; - - redirector = new AppDelegateRedirector(); - - if (JUCEApplicationBase::isStandaloneApp()) - { - [NSApp setDelegate: self]; - - [[NSDistributedNotificationCenter defaultCenter] addObserver: self - selector: @selector (broadcastMessageCallback:) - name: AppDelegateRedirector::getBroacastEventName() - object: nil]; - } - else - { - NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - - [center addObserver: self selector: @selector (applicationDidResignActive:) - name: NSApplicationDidResignActiveNotification object: NSApp]; - - [center addObserver: self selector: @selector (applicationDidBecomeActive:) - name: NSApplicationDidBecomeActiveNotification object: NSApp]; - - [center addObserver: self selector: @selector (applicationWillUnhide:) - name: NSApplicationWillUnhideNotification object: NSApp]; - } - - return self; -} - -- (void) dealloc -{ - redirector->deleteSelf(); - [super dealloc]; -} - -- (void) unregisterObservers -{ - [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: self]; - [[NSNotificationCenter defaultCenter] removeObserver: self]; - - if (JUCEApplicationBase::isStandaloneApp()) - { - [NSApp setDelegate: nil]; - - [[NSDistributedNotificationCenter defaultCenter] removeObserver: self - name: AppDelegateRedirector::getBroacastEventName() - object: nil]; - } -} - -- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app -{ - (void) app; - return redirector->shouldTerminate(); -} - -- (void) applicationWillTerminate: (NSNotification*) aNotification -{ - (void) aNotification; - redirector->willTerminate(); -} - -- (BOOL) application: (NSApplication*) app openFile: (NSString*) filename -{ - (void) app; - return redirector->openFile (filename); -} - -- (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames -{ - (void) sender; - return redirector->openFiles (filenames); -} - -- (void) applicationDidBecomeActive: (NSNotification*) notification -{ - (void) notification; - redirector->focusChanged(); -} - -- (void) applicationDidResignActive: (NSNotification*) notification -{ - (void) notification; - redirector->focusChanged(); -} - -- (void) applicationWillUnhide: (NSNotification*) notification -{ - (void) notification; - redirector->focusChanged(); -} - -- (void) broadcastMessageCallback: (NSNotification*) n -{ - NSDictionary* dict = (NSDictionary*) [n userInfo]; - const String messageString (nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")])); - MessageManager::getInstance()->deliverBroadcastMessage (messageString); -} - -- (void) dummyMethod {} // (used as a way of running a dummy thread) - -@end - -//============================================================================== -namespace juce -{ - -static JuceAppDelegate* juceAppDelegate = nil; - void MessageManager::runDispatchLoop() { if (! quitMessagePosted) // check that the quit message wasn't already posted.. @@ -338,33 +260,52 @@ void initialiseNSApplication() [NSApplication sharedApplication]; } +//============================================================================== +struct AppDelegateHolder +{ +public: + AppDelegateHolder() + : delegate ([AppDelegateClass::createInstance() init]) + {} + + ~AppDelegateHolder() + { + [delegate performSelector: @selector (unregisterObservers)]; + [delegate release]; + } + + id delegate; + CFRunLoopRef runLoop; + CFRunLoopSourceRef runLoopSource; + MessageQueue messageQueue; +}; + +static AppDelegateHolder* appDelegate = nullptr; + void MessageManager::doPlatformSpecificInitialisation() { - if (juceAppDelegate == nil) - juceAppDelegate = [[JuceAppDelegate alloc] init]; + if (appDelegate == nil) + appDelegate = new AppDelegateHolder(); #if ! (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) // This launches a dummy thread, which forces Cocoa to initialise NSThreads correctly (needed prior to 10.5) if (! [NSThread isMultiThreaded]) [NSThread detachNewThreadSelector: @selector (dummyMethod) - toTarget: juceAppDelegate + toTarget: appDelegate->delegate withObject: nil]; #endif } void MessageManager::doPlatformSpecificShutdown() { - if (juceAppDelegate != nil) - { - [juceAppDelegate unregisterObservers]; - [juceAppDelegate release]; - juceAppDelegate = nil; - } + delete appDelegate; + appDelegate = nullptr; } bool MessageManager::postMessageToSystemQueue (MessageBase* message) { - juceAppDelegate->redirector->postMessage (message); + jassert (appDelegate != nil); + appDelegate->messageQueue.post (message); return true; } @@ -373,7 +314,7 @@ void MessageManager::broadcastMessage (const String& message) NSDictionary* info = [NSDictionary dictionaryWithObject: juceStringToNS (message) forKey: nsStringLiteral ("message")]; - [[NSDistributedNotificationCenter defaultCenter] postNotificationName: AppDelegateRedirector::getBroacastEventName() + [[NSDistributedNotificationCenter defaultCenter] postNotificationName: AppDelegateClass::getBroacastEventName() object: nil userInfo: info]; } diff --git a/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm index 05ade32a69..c59de998ce 100644 --- a/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm @@ -28,8 +28,6 @@ class UIViewComponentPeer; //============================================================================== } // (juce namespace) -#define JuceUIView MakeObjCClassName(JuceUIView) - @interface JuceUIView : UIView { @public @@ -54,9 +52,7 @@ class UIViewComponentPeer; - (BOOL) textView: (UITextView*) textView shouldChangeTextInRange: (NSRange) range replacementText: (NSString*) text; @end - -#define JuceUIViewController MakeObjCClassName(JuceUIViewController) - +//============================================================================== @interface JuceUIViewController : UIViewController { } @@ -66,8 +62,6 @@ class UIViewComponentPeer; @end //============================================================================== -#define JuceUIWindow MakeObjCClassName(JuceUIWindow) - @interface JuceUIWindow : UIWindow { @private