From 56c2fcf071226cb4bb9db1b6d64b6fcaf96bdc4b Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 16 Dec 2008 21:08:01 +0000 Subject: [PATCH] fixed a small problem when mac plugins are opened and closed quickly by the host --- .../juce_mac_MessageManager.mm | 22 ++++++++++++++++++- .../macosx/jucedemo.xcodeproj/project.pbxproj | 4 ++++ extras/juce demo/build/win32_vc8/jucedemo.sln | 3 --- juce_amalgamated.cpp | 22 ++++++++++++++++++- juce_amalgamated.h | 4 ++++ .../audio/processors/juce_AudioProcessor.h | 4 ++++ 6 files changed, 54 insertions(+), 5 deletions(-) diff --git a/build/macosx/platform_specific_code/juce_mac_MessageManager.mm b/build/macosx/platform_specific_code/juce_mac_MessageManager.mm index 413f4c0601..224b329237 100644 --- a/build/macosx/platform_specific_code/juce_mac_MessageManager.mm +++ b/build/macosx/platform_specific_code/juce_mac_MessageManager.mm @@ -112,6 +112,9 @@ using namespace JUCE_NAMESPACE; #define JuceAppDelegate MakeObjCClassName(JuceAppDelegate) +static int numPendingMessages = 0; +static bool flushingMessages = false; + @interface JuceAppDelegate : NSObject { @private @@ -139,6 +142,8 @@ using namespace JUCE_NAMESPACE; [super init]; redirector = new AppDelegateRedirector(); + numPendingMessages = 0; + flushingMessages = false; NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; @@ -205,11 +210,13 @@ using namespace JUCE_NAMESPACE; - (void) customEvent: (id) n { + atomicDecrement (numPendingMessages); + NSData* data = (NSData*) n; void* message = 0; [data getBytes: &message length: sizeof (message)]; - if (message != 0) + if (message != 0 && ! flushingMessages) redirector->deliverMessage (message); [data release]; @@ -303,12 +310,25 @@ 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.. + for (int i = 100; --i >= 0 && numPendingMessages > 0;) + { + flushingMessages = true; + getInstance()->runDispatchLoopUntil (10); + } + + jassert (numPendingMessages == 0); // failed to get all the pending messages cleared before quitting.. + [juceAppDelegate release]; juceAppDelegate = 0; } bool juce_postMessageToSystemQueue (void* message) { + atomicIncrement (numPendingMessages); + [juceAppDelegate performSelectorOnMainThread: @selector (customEvent:) withObject: (id) [[NSData alloc] initWithBytes: &message length: (int) sizeof (message)] diff --git a/extras/juce demo/build/macosx/jucedemo.xcodeproj/project.pbxproj b/extras/juce demo/build/macosx/jucedemo.xcodeproj/project.pbxproj index 1b1494c5be..56a2780ec8 100644 --- a/extras/juce demo/build/macosx/jucedemo.xcodeproj/project.pbxproj +++ b/extras/juce demo/build/macosx/jucedemo.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 847F4EB90E8BA9DD00F64426 /* BinaryData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4EB10E8BA9DD00F64426 /* BinaryData.cpp */; }; 847F4EBA0E8BA9DD00F64426 /* juce_LibrarySource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 847F4EB40E8BA9DD00F64426 /* juce_LibrarySource.mm */; }; 847F4EBB0E8BA9DD00F64426 /* MainDemoWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4EB60E8BA9DD00F64426 /* MainDemoWindow.cpp */; }; + 84FFCF3B0EDAFE7F007D5302 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFCF3A0EDAFE7F007D5302 /* Carbon.framework */; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; /* End PBXBuildFile section */ @@ -64,6 +65,7 @@ 847F4EB50E8BA9DD00F64426 /* jucedemo_headers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jucedemo_headers.h; path = ../../src/jucedemo_headers.h; sourceTree = SOURCE_ROOT; }; 847F4EB60E8BA9DD00F64426 /* MainDemoWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MainDemoWindow.cpp; path = ../../src/MainDemoWindow.cpp; sourceTree = SOURCE_ROOT; }; 847F4EB70E8BA9DD00F64426 /* MainDemoWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MainDemoWindow.h; path = ../../src/MainDemoWindow.h; sourceTree = SOURCE_ROOT; }; + 84FFCF3A0EDAFE7F007D5302 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* jucedemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = jucedemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -82,6 +84,7 @@ 841FE4410E8ABDD4003C3263 /* WebKit.framework in Frameworks */, 847F4D900E8AC35C00F64426 /* QTKit.framework in Frameworks */, 8450577A0EB52CE500029DFF /* QuickTime.framework in Frameworks */, + 84FFCF3B0EDAFE7F007D5302 /* Carbon.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -134,6 +137,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + 84FFCF3A0EDAFE7F007D5302 /* Carbon.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 841FE4360E8ABDD4003C3263 /* CoreAudio.framework */, 841FE4370E8ABDD4003C3263 /* CoreMIDI.framework */, diff --git a/extras/juce demo/build/win32_vc8/jucedemo.sln b/extras/juce demo/build/win32_vc8/jucedemo.sln index 197f8550c5..a08814acc5 100644 --- a/extras/juce demo/build/win32_vc8/jucedemo.sln +++ b/extras/juce demo/build/win32_vc8/jucedemo.sln @@ -2,9 +2,6 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jucedemo", "jucedemo.vcproj", "{050D65C2-17C4-4EE1-ABCE-BEA9DA83D77A}" - ProjectSection(ProjectDependencies) = postProject - {AE232C11-D91C-4CA1-B24E-8B11A52EFF26} = {AE232C11-D91C-4CA1-B24E-8B11A52EFF26} - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JUCE", "..\..\..\..\build\win32\vc8\JUCE.vcproj", "{AE232C11-D91C-4CA1-B24E-8B11A52EFF26}" EndProject diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 79457f69ce..48ed14c3c2 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -268525,6 +268525,9 @@ using namespace JUCE_NAMESPACE; #define JuceAppDelegate MakeObjCClassName(JuceAppDelegate) +static int numPendingMessages = 0; +static bool flushingMessages = false; + @interface JuceAppDelegate : NSObject { @private @@ -268552,6 +268555,8 @@ using namespace JUCE_NAMESPACE; [super init]; redirector = new AppDelegateRedirector(); + numPendingMessages = 0; + flushingMessages = false; NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; @@ -268618,11 +268623,13 @@ using namespace JUCE_NAMESPACE; - (void) customEvent: (id) n { + atomicDecrement (numPendingMessages); + NSData* data = (NSData*) n; void* message = 0; [data getBytes: &message length: sizeof (message)]; - if (message != 0) + if (message != 0 && ! flushingMessages) redirector->deliverMessage (message); [data release]; @@ -268715,12 +268722,25 @@ 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.. + for (int i = 100; --i >= 0 && numPendingMessages > 0;) + { + flushingMessages = true; + getInstance()->runDispatchLoopUntil (10); + } + + jassert (numPendingMessages == 0); // failed to get all the pending messages cleared before quitting.. + [juceAppDelegate release]; juceAppDelegate = 0; } bool juce_postMessageToSystemQueue (void* message) { + atomicIncrement (numPendingMessages); + [juceAppDelegate performSelectorOnMainThread: @selector (customEvent:) withObject: (id) [[NSData alloc] initWithBytes: &message length: (int) sizeof (message)] diff --git a/juce_amalgamated.h b/juce_amalgamated.h index a0f6645777..ecdae94434 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -27499,6 +27499,10 @@ public: filter will return an empty buffer, but won't block the audio thread like it would do if you use the getCallbackLock() critical section to synchronise access. + If you're going to use this, your processBlock() method must call isSuspended() and + check whether it's suspended or not. If it is, then it should skip doing any real + processing, either emitting silence or passing the input through unchanged. + @see getCallbackLock */ void suspendProcessing (const bool shouldBeSuspended); diff --git a/src/juce_appframework/audio/processors/juce_AudioProcessor.h b/src/juce_appframework/audio/processors/juce_AudioProcessor.h index fbaaa88622..2826bf7f00 100644 --- a/src/juce_appframework/audio/processors/juce_AudioProcessor.h +++ b/src/juce_appframework/audio/processors/juce_AudioProcessor.h @@ -276,6 +276,10 @@ public: filter will return an empty buffer, but won't block the audio thread like it would do if you use the getCallbackLock() critical section to synchronise access. + If you're going to use this, your processBlock() method must call isSuspended() and + check whether it's suspended or not. If it is, then it should skip doing any real + processing, either emitting silence or passing the input through unchanged. + @see getCallbackLock */ void suspendProcessing (const bool shouldBeSuspended);