1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-09 04:30:09 +00:00

Changed the way Mac messaging works internally to avoid shutdown problems with plugins. Updated some iPhone code. Fixed a CoreGraphics line drawing problem.

This commit is contained in:
Julian Storer 2009-11-16 15:19:16 +00:00
parent 9929d71c27
commit 802f850015
15 changed files with 422 additions and 415 deletions

View file

@ -92,8 +92,6 @@ WaitableEvent::~WaitableEvent() throw()
bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
{
EventStruct* const es = (EventStruct*) internal;
bool ok = true;
pthread_mutex_lock (&es->mutex);
if (timeOutMillisecs < 0)
@ -120,16 +118,15 @@ bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
if (pthread_cond_timedwait (&es->condition, &es->mutex, &time) == ETIMEDOUT)
{
ok = false;
break;
pthread_mutex_unlock (&es->mutex);
return false;
}
}
}
es->triggered = false;
pthread_mutex_unlock (&es->mutex);
return ok;
return true;
}
void WaitableEvent::signal() const throw()

View file

@ -71,7 +71,9 @@ BEGIN_JUCE_NAMESPACE
#include "../gui/components/special/juce_SystemTrayIconComponent.h"
#include "../gui/components/filebrowser/juce_FileChooser.h"
#include "../gui/components/lookandfeel/juce_LookAndFeel.h"
#if JUCE_USE_CDBURNER
#include "../audio/audio_file_formats/juce_AudioCDBurner.h"
#endif
#include "../audio/audio_file_formats/juce_AudioCDReader.h"
#include "../audio/audio_sources/juce_AudioSource.h"
#include "../audio/dsp/juce_AudioDataConverters.h"

View file

@ -397,7 +397,7 @@ private:
void interruptionListener (UInt32 inInterruption)
{
if (inInterruption == kAudioSessionBeginInterruption)
/*if (inInterruption == kAudioSessionBeginInterruption)
{
isRunning = false;
AudioOutputUnitStop (audioUnit);
@ -410,7 +410,7 @@ private:
isRunning = true;
propertyChanged (0, 0, 0);
}
}
}*/
if (inInterruption == kAudioSessionEndInterruption)
{

View file

@ -35,83 +35,11 @@ struct CallbackMessagePayload
bool volatile hasBeenExecuted;
};
/* 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
{
public:
AppDelegateRedirector() {}
virtual ~AppDelegateRedirector() {}
virtual BOOL openFile (const NSString* filename)
{
if (JUCEApplication::getInstance() != 0)
{
JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename));
return YES;
}
return NO;
}
virtual void openFiles (NSArray* filenames)
{
StringArray files;
for (unsigned int i = 0; i < [filenames count]; ++i)
files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i]));
if (files.size() > 0 && JUCEApplication::getInstance() != 0)
{
JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" ")));
}
}
virtual void focusChanged()
{
juce_HandleProcessFocusChange();
}
virtual void deliverMessage (void* message)
{
// no need for an mm lock here - deliverMessage locks it
MessageManager::getInstance()->deliverMessage (message);
}
virtual void performCallback (CallbackMessagePayload* pl)
{
pl->result = (*pl->function) (pl->parameter);
pl->hasBeenExecuted = true;
}
virtual void deleteSelf()
{
delete this;
}
};
END_JUCE_NAMESPACE
using namespace JUCE_NAMESPACE;
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate)
static int numPendingMessages = 0;
@interface JuceAppDelegate : NSObject <UIApplicationDelegate>
{
@private
id oldDelegate;
AppDelegateRedirector* redirector;
@public
bool flushingMessages;
}
- (JuceAppDelegate*) init;
@ -122,7 +50,6 @@ static int numPendingMessages = 0;
- (void) applicationWillUnhide: (NSNotification*) aNotification;
- (void) customEvent: (id) data;
- (void) performCallback: (id) info;
- (void) dummyMethod;
@end
@implementation JuceAppDelegate
@ -131,11 +58,6 @@ static int numPendingMessages = 0;
{
[super init];
redirector = new AppDelegateRedirector();
numPendingMessages = 0;
flushingMessages = false;
oldDelegate = [[UIApplication sharedApplication] delegate];
[[UIApplication sharedApplication] setDelegate: self];
return self;
@ -143,44 +65,45 @@ static int numPendingMessages = 0;
- (void) dealloc
{
if (oldDelegate != 0)
[[UIApplication sharedApplication] setDelegate: oldDelegate];
redirector->deleteSelf();
[[UIApplication sharedApplication] setDelegate: nil];
[super dealloc];
}
- (BOOL) application: (UIApplication*) application handleOpenURL: (NSURL*) url
{
return redirector->openFile ([url absoluteString]);
if (JUCEApplication::getInstance() != 0)
{
JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce ([url absoluteString]));
return YES;
}
return NO;
}
- (void) applicationDidBecomeActive: (NSNotification*) aNotification
{
redirector->focusChanged();
juce_HandleProcessFocusChange();
}
- (void) applicationDidResignActive: (NSNotification*) aNotification
{
redirector->focusChanged();
juce_HandleProcessFocusChange();
}
- (void) applicationWillUnhide: (NSNotification*) aNotification
{
redirector->focusChanged();
juce_HandleProcessFocusChange();
}
- (void) customEvent: (id) n
{
atomicDecrement (numPendingMessages);
NSData* data = (NSData*) n;
void* message = 0;
[data getBytes: &message length: sizeof (message)];
[data release];
if (message != 0 && ! flushingMessages)
redirector->deliverMessage (message);
if (message != 0)
MessageManager::getInstance()->deliverMessage (message);
}
- (void) performCallback: (id) info
@ -190,7 +113,10 @@ static int numPendingMessages = 0;
CallbackMessagePayload* pl = (CallbackMessagePayload*) [((NSData*) info) bytes];
if (pl != 0)
redirector->performCallback (pl);
{
pl->result = (*pl->function) (pl->parameter);
pl->hasBeenExecuted = true;
}
}
else
{
@ -198,8 +124,6 @@ static int numPendingMessages = 0;
}
}
- (void) dummyMethod {} // (used as a way of running a dummy thread)
@end
BEGIN_JUCE_NAMESPACE
@ -209,7 +133,6 @@ static JuceAppDelegate* juceAppDelegate = 0;
void MessageManager::runDispatchLoop()
{
jassert (isThisTheMessageThread()); // must only be called by the message thread
runDispatchLoopUntil (-1);
}
@ -243,30 +166,61 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
}
//==============================================================================
static CFRunLoopTimerRef messageTimer = 0;
static Array <void*, CriticalSection>* pendingMessages = 0;
static void timerCallback (CFRunLoopTimerRef, void*)
{
if (pendingMessages != 0)
{
const int numToDispatch = jmin (4, pendingMessages->size());
for (int i = 0; i < numToDispatch; ++i)
{
void* const nextMessage = (*pendingMessages)[i];
if (nextMessage != 0)
MessageManager::getInstance()->deliverMessage (nextMessage);
}
pendingMessages->removeRange (0, numToDispatch);
if (pendingMessages->size() > 0)
CFRunLoopTimerSetNextFireDate (messageTimer, CFAbsoluteTimeGetCurrent() - 0.5);
}
}
void MessageManager::doPlatformSpecificInitialisation()
{
pendingMessages = new Array <void*, CriticalSection>();
messageTimer = CFRunLoopTimerCreate (kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 60.0, 60.0,
0, 0, timerCallback, 0);
CFRunLoopAddTimer (CFRunLoopGetMain(), messageTimer, kCFRunLoopCommonModes);
if (juceAppDelegate == 0)
juceAppDelegate = [[JuceAppDelegate alloc] init];
}
void MessageManager::doPlatformSpecificShutdown()
{
CFRunLoopTimerInvalidate (messageTimer);
CFRunLoopRemoveTimer (CFRunLoopGetMain(), messageTimer, kCFRunLoopCommonModes);
CFRelease (messageTimer);
messageTimer = 0;
if (pendingMessages != 0)
{
while (pendingMessages->size() > 0)
delete ((Message*) pendingMessages->remove(0));
deleteAndZero (pendingMessages);
}
if (juceAppDelegate != 0)
{
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate];
[[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate];
// Annoyingly, cancelPerformSelectorsWithTarget can't actually cancel the messages
// sent by performSelectorOnMainThread, so need to manually flush these before quitting..
juceAppDelegate->flushingMessages = true;
for (int i = 100; --i >= 0 && numPendingMessages > 0;)
{
const ScopedAutoReleasePool pool;
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: 5 * 0.001]];
}
[juceAppDelegate release];
juceAppDelegate = 0;
}
@ -274,11 +228,12 @@ void MessageManager::doPlatformSpecificShutdown()
bool juce_postMessageToSystemQueue (void* message)
{
atomicIncrement (numPendingMessages);
if (pendingMessages != 0)
{
pendingMessages->add (message);
CFRunLoopTimerSetNextFireDate (messageTimer, CFAbsoluteTimeGetCurrent() - 1.0);
}
[juceAppDelegate performSelectorOnMainThread: @selector (customEvent:)
withObject: (id) [[NSData alloc] initWithBytes: &message length: (int) sizeof (message)]
waitUntilDone: NO];
return true;
}

View file

@ -47,10 +47,9 @@ END_JUCE_NAMESPACE
- (void) applicationDidFinishLaunching: (UIApplication*) application
{
String dummy;
if (! juce_intialisingApp->initialiseApp (dummy))
{
// (should quit)
}
exit (0);
}
- (void) applicationWillResignActive: (UIApplication*) application

View file

@ -132,7 +132,7 @@ public:
UIWindow* window;
JuceUIView* view;
bool isSharedWindow, fullScreen;
bool isSharedWindow, fullScreen, insideDrawRect;
};
//==============================================================================
@ -344,7 +344,8 @@ UIViewComponentPeer::UIViewComponentPeer (Component* const component,
window (0),
view (0),
isSharedWindow (viewToAttachTo != 0),
fullScreen (false)
fullScreen (false),
insideDrawRect (false)
{
CGRect r;
r.origin.x = 0;
@ -733,7 +734,10 @@ void UIViewComponentPeer::drawRect (CGRect r)
CGContextConcatCTM (cg, CGAffineTransformMake (1, 0, 0, -1, 0, view.bounds.size.height));
CoreGraphicsContext g (cg, view.bounds.size.height);
insideDrawRect = true;
handlePaint (g);
insideDrawRect = false;
}
bool UIViewComponentPeer::canBecomeKeyWindow()
@ -761,19 +765,33 @@ void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable
}
//==============================================================================
class AsyncRepaintMessage : public CallbackMessage
{
public:
UIViewComponentPeer* const peer;
const Rectangle rect;
AsyncRepaintMessage (UIViewComponentPeer* const peer_, const Rectangle& rect_)
: peer (peer_), rect (rect_)
{
}
void messageCallback()
{
if (ComponentPeer::isValidPeer (peer))
peer->repaint (rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
};
void UIViewComponentPeer::repaint (int x, int y, int w, int h)
{
CGRect r = CGRectMake ((float) x, (float) y, (float) w, (float) h);
if (! MessageManager::getInstance()->isThisTheMessageThread())
if (insideDrawRect || ! MessageManager::getInstance()->isThisTheMessageThread())
{
[view performSelectorOnMainThread: @selector (asyncRepaint:)
withObject: [NSData dataWithBytes: &r length: sizeof (r)]
waitUntilDone: NO];
(new AsyncRepaintMessage (this, Rectangle (x, y, w, h)))->post();
}
else
{
[view setNeedsDisplayInRect: r];
[view setNeedsDisplayInRect: CGRectMake ((float) x, (float) y, (float) w, (float) h)];
}
}

View file

@ -377,7 +377,7 @@ public:
void drawHorizontalLine (const int y, double left, double right)
{
CGContextFillRect (context, CGRectMake (left, y, right - left, 1.0f));
CGContextFillRect (context, CGRectMake (left, flipHeight - (y + 1.0f), right - left, 1.0f));
}
void setFont (const Font& newFont)

View file

@ -48,8 +48,36 @@ struct CallbackMessagePayload
class AppDelegateRedirector
{
public:
AppDelegateRedirector() {}
virtual ~AppDelegateRedirector() {}
AppDelegateRedirector()
{
CFRunLoopTimerContext context;
zerostruct (context);
context.info = this;
timer = CFRunLoopTimerCreate (kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 60.0, 60.0, 0, 0,
AppDelegateRedirector::timerCallbackStatic, &context);
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
CFRunLoopAddTimer (CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
#else
CFRunLoopAddTimer (CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
#endif
}
virtual ~AppDelegateRedirector()
{
CFRunLoopTimerInvalidate (timer);
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
CFRunLoopRemoveTimer (CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
#else
CFRunLoopRemoveTimer (CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
#endif
CFRelease (timer);
while (messages.size() > 0)
delete ((Message*) messages.remove(0));
}
virtual NSApplicationTerminateReply shouldTerminate()
{
@ -90,12 +118,6 @@ public:
juce_HandleProcessFocusChange();
}
virtual void deliverMessage (void* message)
{
// no need for an mm lock here - deliverMessage locks it
MessageManager::getInstance()->deliverMessage (message);
}
virtual void performCallback (CallbackMessagePayload* pl)
{
pl->result = (*pl->function) (pl->parameter);
@ -106,23 +128,54 @@ public:
{
delete this;
}
void postMessage (void* m) throw()
{
messages.add (m);
CFRunLoopTimerSetNextFireDate (timer, CFAbsoluteTimeGetCurrent() - 0.5);
}
private:
CFRunLoopTimerRef timer;
Array <void*, CriticalSection> messages;
void timerCallback() throw()
{
const int numToDispatch = jmin (4, messages.size());
for (int i = 0; i < numToDispatch; ++i)
{
void* const nextMessage = messages[i];
if (nextMessage != 0)
MessageManager::getInstance()->deliverMessage (nextMessage);
}
messages.removeRange (0, numToDispatch);
if (messages.size() > 0)
CFRunLoopTimerSetNextFireDate (timer, CFAbsoluteTimeGetCurrent() - 0.5);
}
static void timerCallbackStatic (CFRunLoopTimerRef, void* info)
{
((AppDelegateRedirector*) info)->timerCallback();
}
};
END_JUCE_NAMESPACE
using namespace JUCE_NAMESPACE;
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate)
static int numPendingMessages = 0;
@interface JuceAppDelegate : NSObject
{
@private
id oldDelegate;
AppDelegateRedirector* redirector;
@public
bool flushingMessages;
AppDelegateRedirector* redirector;
}
- (JuceAppDelegate*) init;
@ -133,7 +186,6 @@ static int numPendingMessages = 0;
- (void) applicationDidBecomeActive: (NSNotification*) aNotification;
- (void) applicationDidResignActive: (NSNotification*) aNotification;
- (void) applicationWillUnhide: (NSNotification*) aNotification;
- (void) customEvent: (id) data;
- (void) performCallback: (id) info;
- (void) dummyMethod;
@end
@ -145,8 +197,6 @@ static int numPendingMessages = 0;
[super init];
redirector = new AppDelegateRedirector();
numPendingMessages = 0;
flushingMessages = false;
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
@ -210,19 +260,6 @@ static int numPendingMessages = 0;
redirector->focusChanged();
}
- (void) customEvent: (id) n
{
atomicDecrement (numPendingMessages);
NSData* data = (NSData*) n;
void* message = 0;
[data getBytes: &message length: sizeof (message)];
[data release];
if (message != 0 && ! flushingMessages)
redirector->deliverMessage (message);
}
- (void) performCallback: (id) info
{
if ([info isKindOfClass: [NSData class]])
@ -400,18 +437,6 @@ void MessageManager::doPlatformSpecificShutdown()
{
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate];
[[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate];
// Annoyingly, cancelPerformSelectorsWithTarget can't actually cancel the messages
// sent by performSelectorOnMainThread, so need to manually flush these before quitting..
juceAppDelegate->flushingMessages = true;
for (int i = 100; --i >= 0 && numPendingMessages > 0;)
{
const ScopedAutoReleasePool pool;
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
beforeDate: [NSDate dateWithTimeIntervalSinceNow: 5 * 0.001]];
}
[juceAppDelegate release];
juceAppDelegate = 0;
}
@ -419,11 +444,7 @@ void MessageManager::doPlatformSpecificShutdown()
bool juce_postMessageToSystemQueue (void* message)
{
atomicIncrement (numPendingMessages);
[juceAppDelegate performSelectorOnMainThread: @selector (customEvent:)
withObject: (id) [[NSData alloc] initWithBytes: &message length: (int) sizeof (message)]
waitUntilDone: NO];
juceAppDelegate->redirector->postMessage (message);
return true;
}

View file

@ -1531,20 +1531,34 @@ void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable
}
//==============================================================================
class AsyncRepaintMessage : public CallbackMessage
{
public:
NSViewComponentPeer* const peer;
const Rectangle rect;
AsyncRepaintMessage (NSViewComponentPeer* const peer_, const Rectangle& rect_)
: peer (peer_), rect (rect_)
{
}
void messageCallback()
{
if (ComponentPeer::isValidPeer (peer))
peer->repaint (rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
};
void NSViewComponentPeer::repaint (int x, int y, int w, int h)
{
NSRect r = NSMakeRect ((float) x, (float) ([view frame].size.height - (y + h)),
(float) w, (float) h);
if (insideDrawRect)
{
[view performSelectorOnMainThread: @selector (asyncRepaint:)
withObject: [NSData dataWithBytes: &r length: sizeof (r)]
waitUntilDone: NO];
(new AsyncRepaintMessage (this, Rectangle (x, y, w, h)))->post();
}
else
{
[view setNeedsDisplayInRect: r];
[view setNeedsDisplayInRect: NSMakeRect ((float) x, (float) ([view frame].size.height - (y + h)),
(float) w, (float) h)];
}
}