diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index de29cf169d..05cdc9ea67 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -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 (m) != 0) + else { - (dynamic_cast (m))->messageCallback(); + CallbackMessage* const cm = dynamic_cast (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 dotGlyphs; Array 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 { -@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 * 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 (); + + 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 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; } diff --git a/src/application/juce_Application.cpp b/src/application/juce_Application.cpp index 2d8ff9ba71..2ae76e1582 100644 --- a/src/application/juce_Application.cpp +++ b/src/application/juce_Application.cpp @@ -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) diff --git a/src/events/juce_MessageManager.cpp b/src/events/juce_MessageManager.cpp index 9cd7ca16a5..3346f9d811 100644 --- a/src/events/juce_MessageManager.cpp +++ b/src/events/juce_MessageManager.cpp @@ -117,9 +117,12 @@ void MessageManager::deliverMessage (void* message) { quitMessageReceived = true; } - else if (dynamic_cast (m) != 0) + else { - (dynamic_cast (m))->messageCallback(); + CallbackMessage* const cm = dynamic_cast (m); + + if (cm != 0) + cm->messageCallback(); } } } diff --git a/src/gui/components/controls/juce_TextEditor.cpp b/src/gui/components/controls/juce_TextEditor.cpp index 7566535595..17a22294dc 100644 --- a/src/gui/components/controls/juce_TextEditor.cpp +++ b/src/gui/components/controls/juce_TextEditor.cpp @@ -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; diff --git a/src/gui/graphics/fonts/juce_GlyphArrangement.cpp b/src/gui/graphics/fonts/juce_GlyphArrangement.cpp index 0030220141..61c38017bd 100644 --- a/src/gui/graphics/fonts/juce_GlyphArrangement.cpp +++ b/src/gui/graphics/fonts/juce_GlyphArrangement.cpp @@ -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 dotGlyphs; Array 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) { diff --git a/src/gui/graphics/geometry/juce_AffineTransform.cpp b/src/gui/graphics/geometry/juce_AffineTransform.cpp index 04c6796ca3..760d6b84e8 100644 --- a/src/gui/graphics/geometry/juce_AffineTransform.cpp +++ b/src/gui/graphics/geometry/juce_AffineTransform.cpp @@ -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, diff --git a/src/native/common/juce_posix_SharedCode.h b/src/native/common/juce_posix_SharedCode.h index 371af1cb3c..b2fe9c821b 100644 --- a/src/native/common/juce_posix_SharedCode.h +++ b/src/native/common/juce_posix_SharedCode.h @@ -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() diff --git a/src/native/juce_win32_NativeCode.cpp b/src/native/juce_win32_NativeCode.cpp index 6c8df850a7..e017c1b6f3 100644 --- a/src/native/juce_win32_NativeCode.cpp +++ b/src/native/juce_win32_NativeCode.cpp @@ -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" diff --git a/src/native/mac/juce_iphone_Audio.cpp b/src/native/mac/juce_iphone_Audio.cpp index 64eb2343a6..cee26c2256 100644 --- a/src/native/mac/juce_iphone_Audio.cpp +++ b/src/native/mac/juce_iphone_Audio.cpp @@ -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) { diff --git a/src/native/mac/juce_iphone_MessageManager.mm b/src/native/mac/juce_iphone_MessageManager.mm index efb2a30926..ead94802c1 100644 --- a/src/native/mac/juce_iphone_MessageManager.mm +++ b/src/native/mac/juce_iphone_MessageManager.mm @@ -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 { -@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 * 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 (); + + 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; } diff --git a/src/native/mac/juce_iphone_MiscUtilities.mm b/src/native/mac/juce_iphone_MiscUtilities.mm index ce530d63d2..675ededb10 100644 --- a/src/native/mac/juce_iphone_MiscUtilities.mm +++ b/src/native/mac/juce_iphone_MiscUtilities.mm @@ -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 diff --git a/src/native/mac/juce_iphone_UIViewComponentPeer.mm b/src/native/mac/juce_iphone_UIViewComponentPeer.mm index 3647b2889a..6516ad26df 100644 --- a/src/native/mac/juce_iphone_UIViewComponentPeer.mm +++ b/src/native/mac/juce_iphone_UIViewComponentPeer.mm @@ -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)]; } } diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index 51afa1bc60..8cc0b540e7 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -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) diff --git a/src/native/mac/juce_mac_MessageManager.mm b/src/native/mac/juce_mac_MessageManager.mm index 751d6bae6c..2f249e320d 100644 --- a/src/native/mac/juce_mac_MessageManager.mm +++ b/src/native/mac/juce_mac_MessageManager.mm @@ -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 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; } diff --git a/src/native/mac/juce_mac_NSViewComponentPeer.mm b/src/native/mac/juce_mac_NSViewComponentPeer.mm index def0885dc6..ca1bc79edd 100644 --- a/src/native/mac/juce_mac_NSViewComponentPeer.mm +++ b/src/native/mac/juce_mac_NSViewComponentPeer.mm @@ -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)]; } }