Browse Source

Helper class for dynamically building Obj-C classes, and conversion of internal app delegate class to use this.

tags/2021-05-28
jules 13 years ago
parent
commit
2cf53557f6
5 changed files with 178 additions and 201 deletions
  1. +0
    -6
      extras/Introjucer/Source/Project/jucer_AudioPluginModule.h
  2. +3
    -0
      modules/juce_core/native/juce_BasicNativeHeaders.h
  3. +45
    -0
      modules/juce_core/native/juce_osx_ObjCHelpers.h
  4. +129
    -188
      modules/juce_events/native/juce_mac_MessageManager.mm
  5. +1
    -7
      modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm

+ 0
- 6
extras/Introjucer/Source/Project/jucer_AudioPluginModule.h View File

@@ -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())


+ 3
- 0
modules/juce_core/native/juce_BasicNativeHeaders.h View File

@@ -62,6 +62,9 @@
#include <net/if_dl.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h>
#include <objc/runtime.h>
#include <objc/objc.h>
#include <objc/message.h>
//==============================================================================
#elif JUCE_WINDOWS


+ 45
- 0
modules/juce_core/native/juce_osx_ObjCHelpers.h View File

@@ -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 <typename Type>
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 <typename FunctionType>
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__

+ 129
- 188
modules/juce_events/native/juce_mac_MessageManager.mm View File

@@ -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];
}

+ 1
- 7
modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm View File

@@ -28,8 +28,6 @@ class UIViewComponentPeer;
//==============================================================================
} // (juce namespace)
#define JuceUIView MakeObjCClassName(JuceUIView)
@interface JuceUIView : UIView <UITextViewDelegate>
{
@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


Loading…
Cancel
Save