From 5c63c3746c16e45089caa3c3ee55e000444e5b37 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Fri, 17 Sep 2010 12:00:40 +0100 Subject: [PATCH] Fixed a mac app shutdown issue. --- juce_amalgamated.cpp | 141 ++++++++++++-------- juce_amalgamated.h | 4 +- src/application/juce_Application.cpp | 40 ++++-- src/application/juce_Application.h | 2 + src/core/juce_StandardHeader.h | 2 +- src/native/mac/juce_iphone_MiscUtilities.mm | 6 +- src/native/mac/juce_mac_MessageManager.mm | 24 ++-- 7 files changed, 132 insertions(+), 87 deletions(-) diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index d86b6cd3c7..4b3cb0fa65 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -7924,7 +7924,7 @@ public: expect (tempFile.exists()); expect (tempFile.getSize() == 10); - expect (std::abs (tempFile.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds()) < 3000); + expect (std::abs ((int64) (tempFile.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds())) < 3000); expect (tempFile.loadFileAsString() == "0123456789"); expect (! demoFolder.containsSubDirectories()); @@ -7945,7 +7945,7 @@ public: Time t (Time::getCurrentTime()); tempFile.setLastModificationTime (t); Time t2 = tempFile.getLastModificationTime(); - expect (std::abs (t2.toMilliseconds() - t.toMilliseconds()) <= 1000); + expect (std::abs ((int64) (t2.toMilliseconds() - t.toMilliseconds())) <= 1000); { MemoryBlock mb; @@ -9511,55 +9511,62 @@ const StringPairArray& URL::getMimeTypesOfUploadFiles() const const String URL::removeEscapeChars (const String& s) { String result (s.replaceCharacter ('+', ' ')); - int nextPercent = 0; - for (;;) - { - nextPercent = result.indexOfChar (nextPercent, '%'); - - if (nextPercent < 0) - break; + if (! result.containsChar ('%')) + return result; - int hexDigit1 = 0, hexDigit2 = 0; + // We need to operate on the string as raw UTF8 chars, and then recombine them into unicode + // after all the replacements have been made, so that multi-byte chars are handled. + Array utf8 (result.toUTF8(), result.getNumBytesAsUTF8()); - if ((hexDigit1 = CharacterFunctions::getHexDigitValue (result [nextPercent + 1])) >= 0 - && (hexDigit2 = CharacterFunctions::getHexDigitValue (result [nextPercent + 2])) >= 0) + for (int i = 0; i < utf8.size(); ++i) + { + if (utf8.getUnchecked(i) == '%') { - const juce_wchar replacementChar = (juce_wchar) ((hexDigit1 << 4) + hexDigit2); - result = result.replaceSection (nextPercent, 3, String::charToString (replacementChar)); - } + const int hexDigit1 = CharacterFunctions::getHexDigitValue (utf8 [i + 1]); + const int hexDigit2 = CharacterFunctions::getHexDigitValue (utf8 [i + 2]); - ++nextPercent; + if (hexDigit1 >= 0 && hexDigit2 >= 0) + { + utf8.set (i, (char) ((hexDigit1 << 4) + hexDigit2)); + utf8.removeRange (i + 1, 2); + } + } } - return result; + return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size()); } const String URL::addEscapeChars (const String& s, const bool isParameter) { - String result; - result.preallocateStorage (s.length() + 8); - const char* utf8 = s.toUTF8(); - const char* legalChars = isParameter ? "_-.*!'()" - : "_-$.*!'(),"; + const char* const legalChars = isParameter ? "_-.*!'()" + : ",$_-.*!'()"; + + Array utf8 (s.toUTF8(), s.getNumBytesAsUTF8()); - while (*utf8 != 0) + for (int i = 0; i < utf8.size(); ++i) { - const char c = *utf8++; + const char c = utf8.getUnchecked(i); - if (CharacterFunctions::isLetterOrDigit (c) - || CharacterFunctions::indexOfChar (legalChars, c, false) >= 0) - { - result << c; - } - else + if (! (CharacterFunctions::isLetterOrDigit (c) + || CharacterFunctions::indexOfChar (legalChars, c, false) >= 0)) { - const int v = (int) (uint8) c; - result << (v < 0x10 ? "%0" : "%") << String::toHexString (v); + if (c == ' ') + { + utf8.set (i, '+'); + } + else + { + static const char* const hexDigits = "0123456789abcdef"; + + utf8.set (i, '%'); + utf8.insert (++i, hexDigits [((uint8) c) >> 4]); + utf8.insert (++i, hexDigits [c & 15]); + } } } - return result; + return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size()); } bool URL::launchInDefaultBrowser() const @@ -18934,24 +18941,42 @@ int JUCEApplication::shutdownApp() return getApplicationReturnValue(); } +// This is called on the Mac and iOS where the OS doesn't allow the stack to unwind on shutdown.. +void JUCEApplication::appWillTerminateByForce() +{ + { + const ScopedPointer app (JUCEApplication::getInstance()); + + if (app != 0) + app->shutdownApp(); + } + + shutdownJuce_GUI(); +} + int JUCEApplication::main (const String& commandLine) { ScopedJuceInitialiser_GUI libraryInitialiser; - jassert (createInstance != 0); - const ScopedPointer app (createInstance()); + int returnCode = 0; - if (! app->initialiseApp (commandLine)) - return 0; - - JUCE_TRY { - // loop until a quit message is received.. - MessageManager::getInstance()->runDispatchLoop(); + const ScopedPointer app (createInstance()); + + if (! app->initialiseApp (commandLine)) + return 0; + + JUCE_TRY + { + // loop until a quit message is received.. + MessageManager::getInstance()->runDispatchLoop(); + } + JUCE_CATCH_EXCEPTION + + returnCode = app->shutdownApp(); } - JUCE_CATCH_EXCEPTION - return app->shutdownApp(); + return returnCode; } #if JUCE_IOS @@ -265723,11 +265748,7 @@ END_JUCE_NAMESPACE - (void) applicationWillTerminate: (UIApplication*) application { - jassert (JUCEApplication::getInstance() != 0); - JUCEApplication::getInstance()->shutdownApp(); - - delete JUCEApplication::getInstance(); - shutdownJuce_GUI(); + JUCEApplication::appWillTerminateByForce(); } @end @@ -276679,21 +276700,18 @@ public: { JUCEApplication::getInstance()->systemRequestedQuit(); - if (MessageManager::getInstance()->hasStopMessageBeenSent()) - { - [NSApp performSelectorOnMainThread: @selector (replyToApplicationShouldTerminate:) - withObject: [NSNumber numberWithBool: YES] - waitUntilDone: NO]; - - return NSTerminateLater; - } - - return NSTerminateCancel; + if (! MessageManager::getInstance()->hasStopMessageBeenSent()) + return NSTerminateCancel; } return NSTerminateNow; } + virtual void willTerminate() + { + JUCEApplication::appWillTerminateByForce(); + } + virtual BOOL openFile (const NSString* filename) { if (JUCEApplication::getInstance() != 0) @@ -276804,6 +276822,7 @@ using namespace JUCE_NAMESPACE; - (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename; - (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames; - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app; +- (void) applicationWillTerminate: (NSNotification*) aNotification; - (void) applicationDidBecomeActive: (NSNotification*) aNotification; - (void) applicationDidResignActive: (NSNotification*) aNotification; - (void) applicationWillUnhide: (NSNotification*) aNotification; @@ -276857,6 +276876,12 @@ using namespace JUCE_NAMESPACE; return redirector->shouldTerminate(); } +- (void) applicationWillTerminate: (NSNotification*) aNotification +{ + (void) aNotification; + redirector->willTerminate(); +} + - (BOOL) application: (NSApplication*) app openFile: (NSString*) filename { (void) app; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 23f47a64cd..fd06844fd4 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 65 +#define JUCE_BUILDNUMBER 66 /** Current Juce version number. @@ -28474,6 +28474,8 @@ public: /** @internal */ int shutdownApp(); /** @internal */ + static void appWillTerminateByForce(); + /** @internal */ typedef JUCEApplication* (*CreateInstanceFunction)(); /** @internal */ static CreateInstanceFunction createInstance; diff --git a/src/application/juce_Application.cpp b/src/application/juce_Application.cpp index bf6242153e..26d3e27bdd 100644 --- a/src/application/juce_Application.cpp +++ b/src/application/juce_Application.cpp @@ -28,9 +28,7 @@ BEGIN_JUCE_NAMESPACE #include "juce_Application.h" -#include "../utilities/juce_DeletedAtShutdown.h" #include "../events/juce_MessageManager.h" -#include "../core/juce_Time.h" #include "../core/juce_Initialisation.h" #include "../threads/juce_Process.h" #include "../core/juce_PlatformUtilities.h" @@ -199,25 +197,43 @@ int JUCEApplication::shutdownApp() return getApplicationReturnValue(); } +// This is called on the Mac and iOS where the OS doesn't allow the stack to unwind on shutdown.. +void JUCEApplication::appWillTerminateByForce() +{ + { + const ScopedPointer app (JUCEApplication::getInstance()); + + if (app != 0) + app->shutdownApp(); + } + + shutdownJuce_GUI(); +} + //============================================================================== int JUCEApplication::main (const String& commandLine) { ScopedJuceInitialiser_GUI libraryInitialiser; - jassert (createInstance != 0); - const ScopedPointer app (createInstance()); + int returnCode = 0; - if (! app->initialiseApp (commandLine)) - return 0; - - JUCE_TRY { - // loop until a quit message is received.. - MessageManager::getInstance()->runDispatchLoop(); + const ScopedPointer app (createInstance()); + + if (! app->initialiseApp (commandLine)) + return 0; + + JUCE_TRY + { + // loop until a quit message is received.. + MessageManager::getInstance()->runDispatchLoop(); + } + JUCE_CATCH_EXCEPTION + + returnCode = app->shutdownApp(); } - JUCE_CATCH_EXCEPTION - return app->shutdownApp(); + return returnCode; } #if JUCE_IOS diff --git a/src/application/juce_Application.h b/src/application/juce_Application.h index 0e28d722b7..8c2145b094 100644 --- a/src/application/juce_Application.h +++ b/src/application/juce_Application.h @@ -273,6 +273,8 @@ public: /** @internal */ int shutdownApp(); /** @internal */ + static void appWillTerminateByForce(); + /** @internal */ typedef JUCEApplication* (*CreateInstanceFunction)(); /** @internal */ static CreateInstanceFunction createInstance; diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index c009d02103..59e1de232b 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 65 +#define JUCE_BUILDNUMBER 66 /** Current Juce version number. diff --git a/src/native/mac/juce_iphone_MiscUtilities.mm b/src/native/mac/juce_iphone_MiscUtilities.mm index 2852feaebe..3206a571e5 100644 --- a/src/native/mac/juce_iphone_MiscUtilities.mm +++ b/src/native/mac/juce_iphone_MiscUtilities.mm @@ -52,11 +52,7 @@ END_JUCE_NAMESPACE - (void) applicationWillTerminate: (UIApplication*) application { - jassert (JUCEApplication::getInstance() != 0); - JUCEApplication::getInstance()->shutdownApp(); - - delete JUCEApplication::getInstance(); - shutdownJuce_GUI(); + JUCEApplication::appWillTerminateByForce(); } @end diff --git a/src/native/mac/juce_mac_MessageManager.mm b/src/native/mac/juce_mac_MessageManager.mm index e30a27007a..a6bdfa64c5 100644 --- a/src/native/mac/juce_mac_MessageManager.mm +++ b/src/native/mac/juce_mac_MessageManager.mm @@ -70,21 +70,18 @@ public: { JUCEApplication::getInstance()->systemRequestedQuit(); - if (MessageManager::getInstance()->hasStopMessageBeenSent()) - { - [NSApp performSelectorOnMainThread: @selector (replyToApplicationShouldTerminate:) - withObject: [NSNumber numberWithBool: YES] - waitUntilDone: NO]; - - return NSTerminateLater; - } - - return NSTerminateCancel; + if (! MessageManager::getInstance()->hasStopMessageBeenSent()) + return NSTerminateCancel; } return NSTerminateNow; } + virtual void willTerminate() + { + JUCEApplication::appWillTerminateByForce(); + } + virtual BOOL openFile (const NSString* filename) { if (JUCEApplication::getInstance() != 0) @@ -197,6 +194,7 @@ using namespace JUCE_NAMESPACE; - (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename; - (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames; - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app; +- (void) applicationWillTerminate: (NSNotification*) aNotification; - (void) applicationDidBecomeActive: (NSNotification*) aNotification; - (void) applicationDidResignActive: (NSNotification*) aNotification; - (void) applicationWillUnhide: (NSNotification*) aNotification; @@ -250,6 +248,12 @@ using namespace JUCE_NAMESPACE; return redirector->shouldTerminate(); } +- (void) applicationWillTerminate: (NSNotification*) aNotification +{ + (void) aNotification; + redirector->willTerminate(); +} + - (BOOL) application: (NSApplication*) app openFile: (NSString*) filename { (void) app;