1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-15 00:24:19 +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

@ -16344,6 +16344,7 @@ bool JUCEApplication::initialiseApp (String& commandLine)
initialiseJuce_GUI();
#if ! JUCE_IPHONE
jassert (appLock == 0); // initialiseApp must only be called once!
if (! moreThanOneInstanceAllowed())
@ -16361,6 +16362,7 @@ bool JUCEApplication::initialiseApp (String& commandLine)
return false;
}
}
#endif
// let the app do its setting-up..
initialise (commandLineParameters);
@ -16439,9 +16441,9 @@ int JUCEApplication::main (int argc, char* argv[],
return juce_IPhoneMain (argc, argv, newApp);
#else
#if JUCE_MAC
#if JUCE_MAC
const ScopedAutoReleasePool pool;
#endif
#endif
String cmd;
for (int i = 1; i < argc; ++i)
@ -37105,9 +37107,12 @@ void MessageManager::deliverMessage (void* message)
{
quitMessageReceived = true;
}
else if (dynamic_cast <CallbackMessage*> (m) != 0)
else
{
(dynamic_cast <CallbackMessage*> (m))->messageCallback();
CallbackMessage* const cm = dynamic_cast <CallbackMessage*> (m);
if (cm != 0)
cm->messageCallback();
}
}
}
@ -51370,6 +51375,9 @@ public:
atom->getText (passwordCharacter),
atomX, 0.0f);
if (indexToFind - indexInText >= g.getNumGlyphs())
return atomRight;
return jmin (atomRight, g.getGlyph (indexToFind - indexInText).getLeft());
}
@ -51387,7 +51395,7 @@ public:
atomX, 0.0f);
int j;
for (j = 0; j < atom->numChars; ++j)
for (j = 0; j < g.getNumGlyphs(); ++j)
if ((g.getGlyph(j).getLeft() + g.getGlyph(j).getRight()) / 2 > xToFind)
break;
@ -86573,7 +86581,7 @@ void GlyphArrangement::addGlyphArrangement (const GlyphArrangement& other) throw
void GlyphArrangement::removeRangeOfGlyphs (int startIndex, const int num) throw()
{
glyphs.removeRange (startIndex, num);
glyphs.removeRange (startIndex, num < 0 ? glyphs.size() : num);
}
void GlyphArrangement::addLineOfText (const Font& font,
@ -86635,22 +86643,13 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font,
void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) throw()
{
//const TypefaceGlyphInfo* const dotGlyph = font.getTypeface()->getGlyph (T('.'));
if (/*dotGlyph != 0 &&*/ glyphs.size() > 0)
if (glyphs.size() > 0)
{
//PositionedGlyph* glyph = glyphs.getLast();
//const float fontHeight = glyph->font.getHeight();
//const float fontHorizontalScale = glyph->font.getHorizontalScale();
Array<int> dotGlyphs;
Array<float> dotXs;
font.getGlyphPositions (T(".."), dotGlyphs, dotXs);
const float dx = dotXs[1];
//fontHeight * fontHorizontalScale
// * (font.getExtraKerningFactor() + dotGlyph->getHorizontalSpacing (T('.')));
float xOffset = 0.0f, yOffset = 0.0f;
for (int dotPos = 3; --dotPos >= 0 && glyphs.size() > 0;)
@ -86971,7 +86970,7 @@ void GlyphArrangement::addFittedText (const Font& f,
if (startIndex < glyphs.size())
{
glyphs.removeRange (startIndex, glyphs.size());
removeRangeOfGlyphs (startIndex, -1);
if (startIndex - originalStartIndex > 4)
{
@ -88108,8 +88107,8 @@ const AffineTransform AffineTransform::rotation (const float angle,
const AffineTransform AffineTransform::scaled (const float factorX,
const float factorY) const throw()
{
return followedBy (factorX, 0, 0,
0, factorY, 0);
return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02,
factorY * mat10, factorY * mat11, factorY * mat12);
}
const AffineTransform AffineTransform::scale (const float factorX,
@ -234768,6 +234767,10 @@ END_JUCE_NAMESPACE
BEGIN_JUCE_NAMESPACE
#if JUCE_USE_CDBURNER
#endif
#define JUCE_INCLUDED_FILE 1
// Now include the actual code files..
@ -251372,8 +251375,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)
@ -251400,16 +251401,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()
@ -253515,7 +253515,7 @@ void MessageManager::doPlatformSpecificShutdown()
}
}
bool juce_postMessageToSystemQueue (void* message)
bool juce_postMessageToSystemQueue (Message* message)
{
if (errorCondition)
return false;
@ -260845,8 +260845,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)
@ -260873,16 +260871,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()
@ -261790,10 +261787,9 @@ END_JUCE_NAMESPACE
- (void) applicationDidFinishLaunching: (UIApplication*) application
{
String dummy;
if (! juce_intialisingApp->initialiseApp (dummy))
{
// (should quit)
}
exit (0);
}
- (void) applicationWillResignActive: (UIApplication*) application
@ -263076,7 +263072,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)
@ -263470,7 +263466,7 @@ public:
UIWindow* window;
JuceUIView* view;
bool isSharedWindow, fullScreen;
bool isSharedWindow, fullScreen, insideDrawRect;
};
END_JUCE_NAMESPACE
@ -263673,7 +263669,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;
@ -264058,7 +264055,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()
@ -264084,19 +264084,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)];
}
}
@ -264199,83 +264213,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;
@ -264286,7 +264228,6 @@ static int numPendingMessages = 0;
- (void) applicationWillUnhide: (NSNotification*) aNotification;
- (void) customEvent: (id) data;
- (void) performCallback: (id) info;
- (void) dummyMethod;
@end
@implementation JuceAppDelegate
@ -264295,11 +264236,6 @@ static int numPendingMessages = 0;
{
[super init];
redirector = new AppDelegateRedirector();
numPendingMessages = 0;
flushingMessages = false;
oldDelegate = [[UIApplication sharedApplication] delegate];
[[UIApplication sharedApplication] setDelegate: self];
return self;
@ -264307,44 +264243,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
@ -264354,7 +264291,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
{
@ -264362,8 +264302,6 @@ static int numPendingMessages = 0;
}
}
- (void) dummyMethod {} // (used as a way of running a dummy thread)
@end
BEGIN_JUCE_NAMESPACE
@ -264373,7 +264311,6 @@ static JuceAppDelegate* juceAppDelegate = 0;
void MessageManager::runDispatchLoop()
{
jassert (isThisTheMessageThread()); // must only be called by the message thread
runDispatchLoopUntil (-1);
}
@ -264406,30 +264343,61 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
return ! quitMessagePosted;
}
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;
}
@ -264437,11 +264405,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;
}
@ -265795,7 +265764,7 @@ private:
void interruptionListener (UInt32 inInterruption)
{
if (inInterruption == kAudioSessionBeginInterruption)
/*if (inInterruption == kAudioSessionBeginInterruption)
{
isRunning = false;
AudioOutputUnitStop (audioUnit);
@ -265808,7 +265777,7 @@ private:
isRunning = true;
propertyChanged (0, 0, 0);
}
}
}*/
if (inInterruption == kAudioSessionEndInterruption)
{
@ -267529,7 +267498,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)
@ -269305,20 +269274,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)];
}
}
@ -271625,8 +271608,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()
{
@ -271667,12 +271678,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);
@ -271683,6 +271688,39 @@ 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
@ -271690,17 +271728,13 @@ using namespace JUCE_NAMESPACE;
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate)
static int numPendingMessages = 0;
@interface JuceAppDelegate : NSObject
{
@private
id oldDelegate;
AppDelegateRedirector* redirector;
NSTimer* messageTimer;
@public
bool flushingMessages;
AppDelegateRedirector* redirector;
}
- (JuceAppDelegate*) init;
@ -271711,7 +271745,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
@ -271723,8 +271756,6 @@ static int numPendingMessages = 0;
[super init];
redirector = new AppDelegateRedirector();
numPendingMessages = 0;
flushingMessages = false;
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
@ -271788,19 +271819,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]])
@ -271977,18 +271995,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;
}
@ -271996,11 +272002,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

@ -194,6 +194,7 @@ bool JUCEApplication::initialiseApp (String& commandLine)
initialiseJuce_GUI();
#if ! JUCE_IPHONE
jassert (appLock == 0); // initialiseApp must only be called once!
if (! moreThanOneInstanceAllowed())
@ -211,6 +212,7 @@ bool JUCEApplication::initialiseApp (String& commandLine)
return false;
}
}
#endif
// let the app do its setting-up..
initialise (commandLineParameters);
@ -289,9 +291,9 @@ int JUCEApplication::main (int argc, char* argv[],
return juce_IPhoneMain (argc, argv, newApp);
#else
#if JUCE_MAC
#if JUCE_MAC
const ScopedAutoReleasePool pool;
#endif
#endif
String cmd;
for (int i = 1; i < argc; ++i)

View file

@ -117,9 +117,12 @@ void MessageManager::deliverMessage (void* message)
{
quitMessageReceived = true;
}
else if (dynamic_cast <CallbackMessage*> (m) != 0)
else
{
(dynamic_cast <CallbackMessage*> (m))->messageCallback();
CallbackMessage* const cm = dynamic_cast <CallbackMessage*> (m);
if (cm != 0)
cm->messageCallback();
}
}
}

View file

@ -686,6 +686,9 @@ public:
atom->getText (passwordCharacter),
atomX, 0.0f);
if (indexToFind - indexInText >= g.getNumGlyphs())
return atomRight;
return jmin (atomRight, g.getGlyph (indexToFind - indexInText).getLeft());
}
@ -703,7 +706,7 @@ public:
atomX, 0.0f);
int j;
for (j = 0; j < atom->numChars; ++j)
for (j = 0; j < g.getNumGlyphs(); ++j)
if ((g.getGlyph(j).getLeft() + g.getGlyph(j).getRight()) / 2 > xToFind)
break;

View file

@ -159,7 +159,7 @@ void GlyphArrangement::addGlyphArrangement (const GlyphArrangement& other) throw
void GlyphArrangement::removeRangeOfGlyphs (int startIndex, const int num) throw()
{
glyphs.removeRange (startIndex, num);
glyphs.removeRange (startIndex, num < 0 ? glyphs.size() : num);
}
//==============================================================================
@ -222,22 +222,13 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font,
void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) throw()
{
//const TypefaceGlyphInfo* const dotGlyph = font.getTypeface()->getGlyph (T('.'));
if (/*dotGlyph != 0 &&*/ glyphs.size() > 0)
if (glyphs.size() > 0)
{
//PositionedGlyph* glyph = glyphs.getLast();
//const float fontHeight = glyph->font.getHeight();
//const float fontHorizontalScale = glyph->font.getHorizontalScale();
Array<int> dotGlyphs;
Array<float> dotXs;
font.getGlyphPositions (T(".."), dotGlyphs, dotXs);
const float dx = dotXs[1];
//fontHeight * fontHorizontalScale
// * (font.getExtraKerningFactor() + dotGlyph->getHorizontalSpacing (T('.')));
float xOffset = 0.0f, yOffset = 0.0f;
for (int dotPos = 3; --dotPos >= 0 && glyphs.size() > 0;)
@ -558,7 +549,7 @@ void GlyphArrangement::addFittedText (const Font& f,
if (startIndex < glyphs.size())
{
glyphs.removeRange (startIndex, glyphs.size());
removeRangeOfGlyphs (startIndex, -1);
if (startIndex - originalStartIndex > 4)
{

View file

@ -187,8 +187,8 @@ const AffineTransform AffineTransform::rotation (const float angle,
const AffineTransform AffineTransform::scaled (const float factorX,
const float factorY) const throw()
{
return followedBy (factorX, 0, 0,
0, factorY, 0);
return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02,
factorY * mat10, factorY * mat11, factorY * mat12);
}
const AffineTransform AffineTransform::scale (const float factorX,

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