diff --git a/Builds/Linux/Makefile b/Builds/Linux/Makefile index 794f302f33..c341cc3fd5 100644 --- a/Builds/Linux/Makefile +++ b/Builds/Linux/Makefile @@ -119,7 +119,6 @@ OBJECTS := \ $(OBJDIR)/juce_Primes_32e6603.o \ $(OBJDIR)/juce_RSAKey_b60982ae.o \ $(OBJDIR)/juce_ActionBroadcaster_7f997786.o \ - $(OBJDIR)/juce_ActionListenerList_9e099ae4.o \ $(OBJDIR)/juce_AsyncUpdater_a7e1cb89.o \ $(OBJDIR)/juce_ChangeBroadcaster_3eb8fecc.o \ $(OBJDIR)/juce_InterprocessConnection_13086b6d.o \ @@ -763,11 +762,6 @@ $(OBJDIR)/juce_ActionBroadcaster_7f997786.o: ../../src/events/juce_ActionBroadca @echo "Compiling juce_ActionBroadcaster.cpp" @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/juce_ActionListenerList_9e099ae4.o: ../../src/events/juce_ActionListenerList.cpp - -@mkdir -p $(OBJDIR) - @echo "Compiling juce_ActionListenerList.cpp" - @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" - $(OBJDIR)/juce_AsyncUpdater_a7e1cb89.o: ../../src/events/juce_AsyncUpdater.cpp -@mkdir -p $(OBJDIR) @echo "Compiling juce_AsyncUpdater.cpp" diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj index 0b6da29176..95d6fc2654 100644 --- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj @@ -88,7 +88,6 @@ 12E3CC31875A202D6B30F778 = { isa = PBXBuildFile; fileRef = E9E692847C14AD33CD5FB40B; }; CF51988743ED2CD823DFE0B5 = { isa = PBXBuildFile; fileRef = 7AE9331938549244E27A5D0E; }; 659D9CD58B6914EB420E6AEC = { isa = PBXBuildFile; fileRef = 31D985CB8646B78460E9D5A7; }; - 5BE4BAA99FDC6F1B3177096F = { isa = PBXBuildFile; fileRef = 5A46476E16BA4F9DA95E9E6A; }; 55737E2F1817DE642AA7DA05 = { isa = PBXBuildFile; fileRef = 1617348BBF5D103619D76911; }; 6D2C50B0A69855A7F8C062E7 = { isa = PBXBuildFile; fileRef = B80F8CD026033ACCCE11A1A4; }; 70EE7A1273945B62B013DB43 = { isa = PBXBuildFile; fileRef = AE68ECB6E063BD8D4984C0B3; }; @@ -554,8 +553,6 @@ 31D985CB8646B78460E9D5A7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ActionBroadcaster.cpp; path = ../../src/events/juce_ActionBroadcaster.cpp; sourceTree = SOURCE_ROOT; }; 09F7685D1EFF472ECB1F5EF1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ActionBroadcaster.h; path = ../../src/events/juce_ActionBroadcaster.h; sourceTree = SOURCE_ROOT; }; 4EF8BD4BF46C4BCB39F96609 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ActionListener.h; path = ../../src/events/juce_ActionListener.h; sourceTree = SOURCE_ROOT; }; - 5A46476E16BA4F9DA95E9E6A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ActionListenerList.cpp; path = ../../src/events/juce_ActionListenerList.cpp; sourceTree = SOURCE_ROOT; }; - 8269D9DFAD7923EE13E7EEC7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ActionListenerList.h; path = ../../src/events/juce_ActionListenerList.h; sourceTree = SOURCE_ROOT; }; 1617348BBF5D103619D76911 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AsyncUpdater.cpp; path = ../../src/events/juce_AsyncUpdater.cpp; sourceTree = SOURCE_ROOT; }; 44DB44953945417F76199479 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AsyncUpdater.h; path = ../../src/events/juce_AsyncUpdater.h; sourceTree = SOURCE_ROOT; }; D04B6E43A037F985434B2F5A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CallbackMessage.h; path = ../../src/events/juce_CallbackMessage.h; sourceTree = SOURCE_ROOT; }; @@ -1282,8 +1279,6 @@ 31D985CB8646B78460E9D5A7, 09F7685D1EFF472ECB1F5EF1, 4EF8BD4BF46C4BCB39F96609, - 5A46476E16BA4F9DA95E9E6A, - 8269D9DFAD7923EE13E7EEC7, 1617348BBF5D103619D76911, 44DB44953945417F76199479, D04B6E43A037F985434B2F5A, @@ -2008,7 +2003,6 @@ 12E3CC31875A202D6B30F778, CF51988743ED2CD823DFE0B5, 659D9CD58B6914EB420E6AEC, - 5BE4BAA99FDC6F1B3177096F, 55737E2F1817DE642AA7DA05, 6D2C50B0A69855A7F8C062E7, 70EE7A1273945B62B013DB43, diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj index ce011d1ca4..547020d398 100644 --- a/Builds/VisualStudio2005/Juce.vcproj +++ b/Builds/VisualStudio2005/Juce.vcproj @@ -422,8 +422,6 @@ - - diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj index 04fe6697b7..61aca4281c 100644 --- a/Builds/VisualStudio2008/Juce.vcproj +++ b/Builds/VisualStudio2008/Juce.vcproj @@ -422,8 +422,6 @@ - - diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj index d72532cbaa..774a3d752f 100644 --- a/Builds/VisualStudio2008_DLL/Juce.vcproj +++ b/Builds/VisualStudio2008_DLL/Juce.vcproj @@ -424,8 +424,6 @@ - - diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj index 421c1f46c2..36d1e7d1f4 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj +++ b/Builds/VisualStudio2010/Juce.vcxproj @@ -202,7 +202,6 @@ - @@ -550,7 +549,6 @@ - diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters index 6da4c7d4b9..beb04ab046 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj.filters +++ b/Builds/VisualStudio2010/Juce.vcxproj.filters @@ -454,9 +454,6 @@ Juce\Source\events - - Juce\Source\events - Juce\Source\events @@ -1572,9 +1569,6 @@ Juce\Source\events - - Juce\Source\events - Juce\Source\events diff --git a/Builds/iPhone/Juce.xcodeproj/project.pbxproj b/Builds/iPhone/Juce.xcodeproj/project.pbxproj index cdf9877597..54b8718c74 100644 --- a/Builds/iPhone/Juce.xcodeproj/project.pbxproj +++ b/Builds/iPhone/Juce.xcodeproj/project.pbxproj @@ -88,7 +88,6 @@ 12E3CC31875A202D6B30F778 = { isa = PBXBuildFile; fileRef = E9E692847C14AD33CD5FB40B; }; CF51988743ED2CD823DFE0B5 = { isa = PBXBuildFile; fileRef = 7AE9331938549244E27A5D0E; }; 659D9CD58B6914EB420E6AEC = { isa = PBXBuildFile; fileRef = 31D985CB8646B78460E9D5A7; }; - 5BE4BAA99FDC6F1B3177096F = { isa = PBXBuildFile; fileRef = 5A46476E16BA4F9DA95E9E6A; }; 55737E2F1817DE642AA7DA05 = { isa = PBXBuildFile; fileRef = 1617348BBF5D103619D76911; }; 6D2C50B0A69855A7F8C062E7 = { isa = PBXBuildFile; fileRef = B80F8CD026033ACCCE11A1A4; }; 70EE7A1273945B62B013DB43 = { isa = PBXBuildFile; fileRef = AE68ECB6E063BD8D4984C0B3; }; @@ -554,8 +553,6 @@ 31D985CB8646B78460E9D5A7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ActionBroadcaster.cpp; path = ../../src/events/juce_ActionBroadcaster.cpp; sourceTree = SOURCE_ROOT; }; 09F7685D1EFF472ECB1F5EF1 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ActionBroadcaster.h; path = ../../src/events/juce_ActionBroadcaster.h; sourceTree = SOURCE_ROOT; }; 4EF8BD4BF46C4BCB39F96609 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ActionListener.h; path = ../../src/events/juce_ActionListener.h; sourceTree = SOURCE_ROOT; }; - 5A46476E16BA4F9DA95E9E6A = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ActionListenerList.cpp; path = ../../src/events/juce_ActionListenerList.cpp; sourceTree = SOURCE_ROOT; }; - 8269D9DFAD7923EE13E7EEC7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ActionListenerList.h; path = ../../src/events/juce_ActionListenerList.h; sourceTree = SOURCE_ROOT; }; 1617348BBF5D103619D76911 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_AsyncUpdater.cpp; path = ../../src/events/juce_AsyncUpdater.cpp; sourceTree = SOURCE_ROOT; }; 44DB44953945417F76199479 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_AsyncUpdater.h; path = ../../src/events/juce_AsyncUpdater.h; sourceTree = SOURCE_ROOT; }; D04B6E43A037F985434B2F5A = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CallbackMessage.h; path = ../../src/events/juce_CallbackMessage.h; sourceTree = SOURCE_ROOT; }; @@ -1282,8 +1279,6 @@ 31D985CB8646B78460E9D5A7, 09F7685D1EFF472ECB1F5EF1, 4EF8BD4BF46C4BCB39F96609, - 5A46476E16BA4F9DA95E9E6A, - 8269D9DFAD7923EE13E7EEC7, 1617348BBF5D103619D76911, 44DB44953945417F76199479, D04B6E43A037F985434B2F5A, @@ -2008,7 +2003,6 @@ 12E3CC31875A202D6B30F778, CF51988743ED2CD823DFE0B5, 659D9CD58B6914EB420E6AEC, - 5BE4BAA99FDC6F1B3177096F, 55737E2F1817DE642AA7DA05, 6D2C50B0A69855A7F8C062E7, 70EE7A1273945B62B013DB43, diff --git a/Juce.jucer b/Juce.jucer index 050e81d2fa..a8068b6ce4 100644 --- a/Juce.jucer +++ b/Juce.jucer @@ -491,10 +491,6 @@ file="src/events/juce_ActionBroadcaster.h"/> - - (message); + ActionListener* const target = static_cast (am.pointerParameter); + + if (owner->actionListeners.contains (target)) + target->actionListenerCallback (am.message); } -void ActionListenerList::addActionListener (ActionListener* const listener) +ActionBroadcaster::ActionBroadcaster() { - const ScopedLock sl (actionListenerLock_); - - jassert (listener != 0); - jassert (! actionListeners_.contains (listener)); // trying to add a listener to the list twice! + // are you trying to create this object before or after juce has been intialised?? + jassert (MessageManager::instance != 0); - if (listener != 0) - actionListeners_.add (listener); + callback.owner = this; } -void ActionListenerList::removeActionListener (ActionListener* const listener) +ActionBroadcaster::~ActionBroadcaster() { - const ScopedLock sl (actionListenerLock_); + // all event-based objects must be deleted BEFORE juce is shut down! + jassert (MessageManager::instance != 0); +} - jassert (actionListeners_.contains (listener)); // trying to remove a listener that isn't on the list! +void ActionBroadcaster::addActionListener (ActionListener* const listener) +{ + const ScopedLock sl (actionListenerLock); - actionListeners_.removeValue (listener); + if (listener != 0) + actionListeners.add (listener); } -void ActionListenerList::removeAllActionListeners() +void ActionBroadcaster::removeActionListener (ActionListener* const listener) { - const ScopedLock sl (actionListenerLock_); - actionListeners_.clear(); + const ScopedLock sl (actionListenerLock); + actionListeners.removeValue (listener); } -void ActionListenerList::sendActionMessage (const String& message) const +void ActionBroadcaster::removeAllActionListeners() { - const ScopedLock sl (actionListenerLock_); - - for (int i = actionListeners_.size(); --i >= 0;) - postMessage (new ActionMessage (message, static_cast (actionListeners_.getUnchecked(i)))); + const ScopedLock sl (actionListenerLock); + actionListeners.clear(); } -void ActionListenerList::handleMessage (const Message& message) +void ActionBroadcaster::sendActionMessage (const String& message) const { - const ActionMessage& am = (const ActionMessage&) message; + const ScopedLock sl (actionListenerLock); - if (actionListeners_.contains (am.pointerParameter)) - static_cast (am.pointerParameter)->actionListenerCallback (am.message); + for (int i = actionListeners.size(); --i >= 0;) + callback.postMessage (new ActionMessage (message, actionListeners.getUnchecked(i))); } END_JUCE_NAMESPACE -/*** End of inlined file: juce_ActionListenerList.cpp ***/ +/*** End of inlined file: juce_ActionBroadcaster.cpp ***/ /*** Start of inlined file: juce_AsyncUpdater.cpp ***/ BEGIN_JUCE_NAMESPACE +class AsyncUpdater::AsyncUpdaterMessage : public CallbackMessage +{ +public: + AsyncUpdaterMessage (AsyncUpdater& owner_) + : owner (owner_) + { + } + + void messageCallback() + { + if (owner.pendingMessage.compareAndSetBool (0, this)) + owner.handleAsyncUpdate(); + } + + AsyncUpdater& owner; +}; + AsyncUpdater::AsyncUpdater() throw() - : asyncMessagePending (false) { - internalAsyncHandler.owner = this; } AsyncUpdater::~AsyncUpdater() { + // You're deleting this object with a background thread while there's an update + // pending on the main event thread - that's pretty dodgy threading, as the callback could + // happen after this destructor has finished. You should either use a MessageManagerLock while + // deleting this object, or find some other way to avoid such a race condition. + jassert (/*(! isUpdatePending()) ||*/ MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + + pendingMessage = 0; } void AsyncUpdater::triggerAsyncUpdate() { - if (! asyncMessagePending) + if (pendingMessage.value == 0) { - asyncMessagePending = true; - internalAsyncHandler.postMessage (new Message()); + ScopedPointer pending (new AsyncUpdaterMessage (*this)); + + if (pendingMessage.compareAndSetBool (pending, 0)) + pending.release()->post(); } } void AsyncUpdater::cancelPendingUpdate() throw() { - asyncMessagePending = false; + pendingMessage = 0; } void AsyncUpdater::handleUpdateNowIfNeeded() { - if (asyncMessagePending) - { - asyncMessagePending = false; + // This can only be called by the event thread. + jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + + if (pendingMessage.exchange (0) != 0) handleAsyncUpdate(); - } } -void AsyncUpdater::AsyncUpdaterInternal::handleMessage (const Message&) +bool AsyncUpdater::isUpdatePending() const throw() { - owner->handleUpdateNowIfNeeded(); + return pendingMessage.value != 0; } END_JUCE_NAMESPACE @@ -38452,40 +38433,24 @@ END_JUCE_NAMESPACE /*** Start of inlined file: juce_ChangeBroadcaster.cpp ***/ BEGIN_JUCE_NAMESPACE -class ChangeBroadcaster::ChangeBroadcasterMessage : public CallbackMessage -{ -public: - ChangeBroadcasterMessage (ChangeBroadcaster* const owner_) - : owner (owner_) - { - } - - void messageCallback() - { - if (owner != 0 && owner->pendingMessage.value == this) - owner->sendSynchronousChangeMessage(); - } - - ChangeBroadcaster* owner; -}; - ChangeBroadcaster::ChangeBroadcaster() throw() { // are you trying to create this object before or after juce has been intialised?? jassert (MessageManager::instance != 0); + + callback.owner = this; } ChangeBroadcaster::~ChangeBroadcaster() { // all event-based objects must be deleted BEFORE juce is shut down! jassert (MessageManager::instance != 0); - - invalidatePendingMessage(); } void ChangeBroadcaster::addChangeListener (ChangeListener* const listener) { - // Listeners can only be safely added when the event thread is locked... + // Listeners can only be safely added when the event thread is locked + // You can use a MessageManagerLock if you need to call this from another thread. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); changeListeners.add (listener); @@ -38493,7 +38458,8 @@ void ChangeBroadcaster::addChangeListener (ChangeListener* const listener) void ChangeBroadcaster::removeChangeListener (ChangeListener* const listener) { - // Listeners can only be safely added when the event thread is locked... + // Listeners can only be safely added when the event thread is locked + // You can use a MessageManagerLock if you need to call this from another thread. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); changeListeners.remove (listener); @@ -38501,28 +38467,17 @@ void ChangeBroadcaster::removeChangeListener (ChangeListener* const listener) void ChangeBroadcaster::removeAllChangeListeners() { - // Listeners can only be safely added when the event thread is locked... + // Listeners can only be safely added when the event thread is locked + // You can use a MessageManagerLock if you need to call this from another thread. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); changeListeners.clear(); } -void ChangeBroadcaster::invalidatePendingMessage() -{ - ChangeBroadcasterMessage* const oldMessage = pendingMessage.exchange (0); - if (oldMessage != 0) - oldMessage->owner = 0; -} - void ChangeBroadcaster::sendChangeMessage() { - if (pendingMessage.value == 0 && changeListeners.size() > 0) - { - ScopedPointer pending (new ChangeBroadcasterMessage (this)); - - if (pendingMessage.compareAndSetBool (pending, 0)) - pending.release()->post(); - } + if (changeListeners.size() > 0) + callback.triggerAsyncUpdate(); } void ChangeBroadcaster::sendSynchronousChangeMessage() @@ -38530,14 +38485,29 @@ void ChangeBroadcaster::sendSynchronousChangeMessage() // This can only be called by the event thread. jassert (MessageManager::getInstance()->isThisTheMessageThread()); - invalidatePendingMessage(); - changeListeners.call (&ChangeListener::changeListenerCallback, this); + callback.cancelPendingUpdate(); + callListeners(); } void ChangeBroadcaster::dispatchPendingMessages() { - if (pendingMessage.get() != 0) - sendSynchronousChangeMessage(); + callback.handleUpdateNowIfNeeded(); +} + +void ChangeBroadcaster::callListeners() +{ + changeListeners.call (&ChangeListener::changeListenerCallback, this); +} + +ChangeBroadcaster::ChangeBroadcasterCallback::ChangeBroadcasterCallback() + : owner (0) +{ +} + +void ChangeBroadcaster::ChangeBroadcasterCallback::handleAsyncUpdate() +{ + jassert (owner != 0); + owner->callListeners(); } END_JUCE_NAMESPACE @@ -38955,7 +38925,8 @@ Message::Message() throw() : intParameter1 (0), intParameter2 (0), intParameter3 (0), - pointerParameter (0) + pointerParameter (0), + messageRecipient (0) { } @@ -38966,7 +38937,8 @@ Message::Message (const int intParameter1_, : intParameter1 (intParameter1_), intParameter2 (intParameter2_), intParameter3 (intParameter3_), - pointerParameter (pointerParameter_) + pointerParameter (pointerParameter_), + messageRecipient (0) { } @@ -39037,7 +39009,7 @@ MessageManager::MessageManager() throw() MessageManager::~MessageManager() throw() { - broadcastListeners = 0; + broadcaster = 0; doPlatformSpecificShutdown(); @@ -39068,47 +39040,40 @@ void MessageManager::postMessageToQueue (Message* const message) delete message; } -CallbackMessage::CallbackMessage() throw() {} -CallbackMessage::~CallbackMessage() {} +CallbackMessage::CallbackMessage() throw() {} +CallbackMessage::~CallbackMessage() {} void CallbackMessage::post() { if (MessageManager::instance != 0) - MessageManager::instance->postCallbackMessage (this); -} - -void MessageManager::postCallbackMessage (Message* const message) -{ - message->messageRecipient = 0; - postMessageToQueue (message); + MessageManager::instance->postMessageToQueue (this); } // not for public use.. void MessageManager::deliverMessage (Message* const message) { - const ScopedPointer messageDeleter (message); - MessageListener* const recipient = message->messageRecipient; - JUCE_TRY { - if (messageListeners.contains (recipient)) - { - recipient->handleMessage (*message); - } - else if (recipient == 0) + const ScopedPointer messageDeleter (message); + MessageListener* const recipient = message->messageRecipient; + + if (recipient == 0) { - if (message->intParameter1 == quitMessageId) + CallbackMessage* const callbackMessage = dynamic_cast (message); + + if (callbackMessage != 0) { - quitMessageReceived = true; + callbackMessage->messageCallback(); } - else + else if (message->intParameter1 == quitMessageId) { - CallbackMessage* const cm = dynamic_cast (message); - - if (cm != 0) - cm->messageCallback(); + quitMessageReceived = true; } } + else if (messageListeners.contains (recipient)) + { + recipient->handleMessage (*message); + } } JUCE_CATCH_EXCEPTION } @@ -39123,10 +39088,7 @@ void MessageManager::runDispatchLoop() void MessageManager::stopDispatchLoop() { - Message* const m = new Message (quitMessageId, 0, 0, 0); - m->messageRecipient = 0; - postMessageToQueue (m); - + postMessageToQueue (new Message (quitMessageId, 0, 0, 0)); quitMessagePosted = true; } @@ -39159,22 +39121,22 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) void MessageManager::deliverBroadcastMessage (const String& value) { - if (broadcastListeners != 0) - broadcastListeners->sendActionMessage (value); + if (broadcaster != 0) + broadcaster->sendActionMessage (value); } void MessageManager::registerBroadcastListener (ActionListener* const listener) { - if (broadcastListeners == 0) - broadcastListeners = new ActionListenerList(); + if (broadcaster == 0) + broadcaster = new ActionBroadcaster(); - broadcastListeners->addActionListener (listener); + broadcaster->addActionListener (listener); } void MessageManager::deregisterBroadcastListener (ActionListener* const listener) { - if (broadcastListeners != 0) - broadcastListeners->removeActionListener (listener); + if (broadcaster != 0) + broadcaster->removeActionListener (listener); } bool MessageManager::isThisTheMessageThread() const throw() @@ -39213,7 +39175,6 @@ class MessageManagerLock::SharedEvents : public ReferenceCountedObject { public: SharedEvents() {} - ~SharedEvents() {} /* This class just holds a couple of events to communicate between the BlockingMessage and the MessageManagerLock. Because both of these objects may be deleted at any time, @@ -39229,7 +39190,6 @@ class MessageManagerLock::BlockingMessage : public CallbackMessage { public: BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {} - ~BlockingMessage() throw() {} void messageCallback() { diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 556c67e80d..a12922aa19 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 93 +#define JUCE_BUILDNUMBER 94 /** Current Juce version number. @@ -12281,131 +12281,6 @@ private: #ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ #define __JUCE_ASYNCUPDATER_JUCEHEADER__ - -/*** Start of inlined file: juce_MessageListener.h ***/ -#ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ -#define __JUCE_MESSAGELISTENER_JUCEHEADER__ - - -/*** Start of inlined file: juce_Message.h ***/ -#ifndef __JUCE_MESSAGE_JUCEHEADER__ -#define __JUCE_MESSAGE_JUCEHEADER__ - -class MessageListener; -class MessageManager; - -/** The base class for objects that can be delivered to a MessageListener. - - The simplest Message object contains a few integer and pointer parameters - that the user can set, and this is enough for a lot of purposes. For passing more - complex data, subclasses of Message can also be used. - - @see MessageListener, MessageManager, ActionListener, ChangeListener -*/ -class JUCE_API Message -{ -public: - - /** Creates an uninitialised message. - - The class's variables will also be left uninitialised. - */ - Message() throw(); - - /** Creates a message object, filling in the member variables. - - The corresponding public member variables will be set from the parameters - passed in. - */ - Message (int intParameter1, - int intParameter2, - int intParameter3, - void* pointerParameter) throw(); - - /** Destructor. */ - virtual ~Message(); - - // These values can be used for carrying simple data that the application needs to - // pass around. For more complex messages, just create a subclass. - - int intParameter1; /**< user-defined integer value. */ - int intParameter2; /**< user-defined integer value. */ - int intParameter3; /**< user-defined integer value. */ - void* pointerParameter; /**< user-defined pointer value. */ - - juce_UseDebuggingNewOperator - -private: - friend class MessageListener; - friend class MessageManager; - MessageListener* messageRecipient; - - Message (const Message&); - Message& operator= (const Message&); -}; - -#endif // __JUCE_MESSAGE_JUCEHEADER__ -/*** End of inlined file: juce_Message.h ***/ - -/** - MessageListener subclasses can post and receive Message objects. - - @see Message, MessageManager, ActionListener, ChangeListener -*/ -class JUCE_API MessageListener -{ -protected: - - /** Creates a MessageListener. */ - MessageListener() throw(); - -public: - - /** Destructor. - - When a MessageListener is deleted, it removes itself from a global list - of registered listeners, so that the isValidMessageListener() method - will no longer return true. - */ - virtual ~MessageListener(); - - /** This is the callback method that receives incoming messages. - - This is called by the MessageManager from its dispatch loop. - - @see postMessage - */ - virtual void handleMessage (const Message& message) = 0; - - /** Sends a message to the message queue, for asynchronous delivery to this listener - later on. - - This method can be called safely by any thread. - - @param message the message object to send - this will be deleted - automatically by the message queue, so don't keep any - references to it after calling this method. - @see handleMessage - */ - void postMessage (Message* message) const throw(); - - /** Checks whether this MessageListener has been deleted. - - Although not foolproof, this method is safe to call on dangling or null - pointers. A list of active MessageListeners is kept internally, so this - checks whether the object is on this list or not. - - Note that it's possible to get a false-positive here, if an object is - deleted and another is subsequently created that happens to be at the - exact same memory location, but I can't think of a good way of avoiding - this. - */ - bool isValidMessageListener() const throw(); -}; - -#endif // __JUCE_MESSAGELISTENER_JUCEHEADER__ -/*** End of inlined file: juce_MessageListener.h ***/ - /** Has a callback method that is triggered asynchronously. @@ -12454,9 +12329,15 @@ public: Use this as a kind of "flush" operation - if an update is pending, the handleAsyncUpdate() method will be called immediately; if no update is pending, then nothing will be done. + + Because this may invoke the callback, this method must only be called on + the main event thread. */ void handleUpdateNowIfNeeded(); + /** Returns true if there's an update callback in the pipeline. */ + bool isUpdatePending() const throw(); + /** Called back to do whatever your class needs to do. This method is called by the message thread at the next convenient time @@ -12466,23 +12347,10 @@ public: private: - class AsyncUpdaterInternal : public MessageListener - { - public: - AsyncUpdaterInternal() {} - ~AsyncUpdaterInternal() {} - - void handleMessage (const Message&); - - AsyncUpdater* owner; - - private: - AsyncUpdaterInternal (const AsyncUpdaterInternal&); - AsyncUpdaterInternal& operator= (const AsyncUpdaterInternal&); - }; + class AsyncUpdaterMessage; + friend class AsyncUpdaterMessage; - AsyncUpdaterInternal internalAsyncHandler; - bool asyncMessagePending; + Atomic pendingMessage; }; #endif // __JUCE_ASYNCUPDATER_JUCEHEADER__ @@ -13099,13 +12967,20 @@ public: private: - class ChangeBroadcasterMessage; - friend class ChangeBroadcasterMessage; + class ChangeBroadcasterCallback : public AsyncUpdater + { + public: + ChangeBroadcasterCallback(); + void handleAsyncUpdate(); + + ChangeBroadcaster* owner; + }; - Atomic pendingMessage; + friend class ChangeBroadcasterCallback; + ChangeBroadcasterCallback callback; ListenerList changeListeners; - void invalidatePendingMessage(); + void callListeners(); ChangeBroadcaster (const ChangeBroadcaster&); ChangeBroadcaster& operator= (const ChangeBroadcaster&); @@ -28302,6 +28177,131 @@ struct JUCE_API ApplicationCommandInfo #endif // __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ /*** End of inlined file: juce_ApplicationCommandInfo.h ***/ + +/*** Start of inlined file: juce_MessageListener.h ***/ +#ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ +#define __JUCE_MESSAGELISTENER_JUCEHEADER__ + + +/*** Start of inlined file: juce_Message.h ***/ +#ifndef __JUCE_MESSAGE_JUCEHEADER__ +#define __JUCE_MESSAGE_JUCEHEADER__ + +class MessageListener; +class MessageManager; + +/** The base class for objects that can be delivered to a MessageListener. + + The simplest Message object contains a few integer and pointer parameters + that the user can set, and this is enough for a lot of purposes. For passing more + complex data, subclasses of Message can also be used. + + @see MessageListener, MessageManager, ActionListener, ChangeListener +*/ +class JUCE_API Message +{ +public: + + /** Creates an uninitialised message. + + The class's variables will also be left uninitialised. + */ + Message() throw(); + + /** Creates a message object, filling in the member variables. + + The corresponding public member variables will be set from the parameters + passed in. + */ + Message (int intParameter1, + int intParameter2, + int intParameter3, + void* pointerParameter) throw(); + + /** Destructor. */ + virtual ~Message(); + + // These values can be used for carrying simple data that the application needs to + // pass around. For more complex messages, just create a subclass. + + int intParameter1; /**< user-defined integer value. */ + int intParameter2; /**< user-defined integer value. */ + int intParameter3; /**< user-defined integer value. */ + void* pointerParameter; /**< user-defined pointer value. */ + + juce_UseDebuggingNewOperator + +private: + friend class MessageListener; + friend class MessageManager; + MessageListener* messageRecipient; + + Message (const Message&); + Message& operator= (const Message&); +}; + +#endif // __JUCE_MESSAGE_JUCEHEADER__ +/*** End of inlined file: juce_Message.h ***/ + +/** + MessageListener subclasses can post and receive Message objects. + + @see Message, MessageManager, ActionListener, ChangeListener +*/ +class JUCE_API MessageListener +{ +protected: + + /** Creates a MessageListener. */ + MessageListener() throw(); + +public: + + /** Destructor. + + When a MessageListener is deleted, it removes itself from a global list + of registered listeners, so that the isValidMessageListener() method + will no longer return true. + */ + virtual ~MessageListener(); + + /** This is the callback method that receives incoming messages. + + This is called by the MessageManager from its dispatch loop. + + @see postMessage + */ + virtual void handleMessage (const Message& message) = 0; + + /** Sends a message to the message queue, for asynchronous delivery to this listener + later on. + + This method can be called safely by any thread. + + @param message the message object to send - this will be deleted + automatically by the message queue, so don't keep any + references to it after calling this method. + @see handleMessage + */ + void postMessage (Message* message) const throw(); + + /** Checks whether this MessageListener has been deleted. + + Although not foolproof, this method is safe to call on dangling or null + pointers. A list of active MessageListeners is kept internally, so this + checks whether the object is on this list or not. + + Note that it's possible to get a false-positive here, if an object is + deleted and another is subsequently created that happens to be at the + exact same memory location, but I can't think of a good way of avoiding + this. + */ + bool isValidMessageListener() const throw(); +}; + +#endif // __JUCE_MESSAGELISTENER_JUCEHEADER__ +/*** End of inlined file: juce_MessageListener.h ***/ + /** A command target publishes a list of command IDs that it can perform. @@ -28537,7 +28537,7 @@ private: Used by various classes, e.g. buttons when they are pressed, to tell listeners about something that's happened. - @see ActionListenerList, ActionBroadcaster, ChangeListener + @see ActionBroadcaster, ChangeListener */ class JUCE_API ActionListener { @@ -28548,7 +28548,7 @@ public: /** Overridden by your subclass to receive the callback. @param message the string that was specified when the event was triggered - by a call to ActionListenerList::sendActionMessage() + by a call to ActionBroadcaster::sendActionMessage() */ virtual void actionListenerCallback (const String& message) = 0; }; @@ -43380,96 +43380,29 @@ private: #ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__ #define __JUCE_ACTIONBROADCASTER_JUCEHEADER__ - -/*** Start of inlined file: juce_ActionListenerList.h ***/ -#ifndef __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ -#define __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ - -/** - A set of ActionListeners. - - Listeners can be added and removed from the list, and messages can be - broadcast to all the listeners. - - @see ActionListener, ActionBroadcaster -*/ -class JUCE_API ActionListenerList : public MessageListener -{ -public: - - /** Creates an empty list. */ - ActionListenerList(); - - /** Destructor. */ - ~ActionListenerList(); - - /** Adds a listener to the list. - - (Trying to add a listener that's already on the list will have no effect). - */ - void addActionListener (ActionListener* listener); - - /** Removes a listener from the list. - - If the listener isn't on the list, this won't have any effect. - */ - void removeActionListener (ActionListener* listener); - - /** Removes all listeners from the list. */ - void removeAllActionListeners(); - - /** Broadcasts a message to all the registered listeners. - - This sends the message asynchronously. - - If a listener is on the list when this method is called but is removed from - the list before the message arrives, it won't receive the message. Similarly - listeners that are added to the list after the message is sent but before it - arrives won't get the message either. - */ - void sendActionMessage (const String& message) const; - - /** @internal */ - void handleMessage (const Message&); - - juce_UseDebuggingNewOperator - -private: - SortedSet actionListeners_; - CriticalSection actionListenerLock_; - - ActionListenerList (const ActionListenerList&); - ActionListenerList& operator= (const ActionListenerList&); -}; - -#endif // __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ -/*** End of inlined file: juce_ActionListenerList.h ***/ - /** Manages a list of ActionListeners, and can send them messages. To quickly add methods to your class that can add/remove action listeners and broadcast to them, you can derive from this. - @see ActionListenerList, ActionListener + @see ActionListener, ChangeListener */ class JUCE_API ActionBroadcaster { public: /** Creates an ActionBroadcaster. */ - ActionBroadcaster() throw(); + ActionBroadcaster(); /** Destructor. */ virtual ~ActionBroadcaster(); /** Adds a listener to the list. - - (Trying to add a listener that's already on the list will have no effect). + Trying to add a listener that's already on the list will have no effect. */ void addActionListener (ActionListener* listener); /** Removes a listener from the list. - If the listener isn't on the list, this won't have any effect. */ void removeActionListener (ActionListener* listener); @@ -43478,14 +43411,25 @@ public: void removeAllActionListeners(); /** Broadcasts a message to all the registered listeners. - - @see ActionListenerList::sendActionMessage + @see ActionListener::actionListenerCallback */ void sendActionMessage (const String& message) const; private: - ActionListenerList actionListenerList; + class CallbackReceiver : public MessageListener + { + public: + CallbackReceiver(); + void handleMessage (const Message&); + + ActionBroadcaster* owner; + }; + + friend class CallbackReceiver; + CallbackReceiver callback; + SortedSet actionListeners; + CriticalSection actionListenerLock; ActionBroadcaster (const ActionBroadcaster&); ActionBroadcaster& operator= (const ActionBroadcaster&); @@ -43498,9 +43442,6 @@ private: #endif #ifndef __JUCE_ACTIONLISTENER_JUCEHEADER__ -#endif -#ifndef __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ - #endif #ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ @@ -43980,7 +43921,7 @@ private: static MessageManager* instance; SortedSet messageListeners; - ScopedPointer broadcastListeners; + ScopedPointer broadcaster; friend class JUCEApplication; bool quitMessagePosted, quitMessageReceived; @@ -43989,7 +43930,6 @@ private: static void* exitModalLoopCallback (void*); void postMessageToQueue (Message* message); - void postCallbackMessage (Message* message); static void doPlatformSpecificInitialisation(); static void doPlatformSpecificShutdown(); diff --git a/src/application/juce_ApplicationCommandTarget.h b/src/application/juce_ApplicationCommandTarget.h index 1da0819af1..139010f18b 100644 --- a/src/application/juce_ApplicationCommandTarget.h +++ b/src/application/juce_ApplicationCommandTarget.h @@ -28,6 +28,7 @@ #include "../gui/components/juce_Component.h" #include "juce_ApplicationCommandInfo.h" +#include "../events/juce_MessageListener.h" //============================================================================== diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index d6debc3325..b446fb9e43 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 93 +#define JUCE_BUILDNUMBER 94 /** Current Juce version number. diff --git a/src/events/juce_ActionBroadcaster.cpp b/src/events/juce_ActionBroadcaster.cpp index 1d6f537d7d..b241e3666a 100644 --- a/src/events/juce_ActionBroadcaster.cpp +++ b/src/events/juce_ActionBroadcaster.cpp @@ -29,13 +29,45 @@ BEGIN_JUCE_NAMESPACE #include "juce_ActionBroadcaster.h" #include "juce_MessageManager.h" +#include "../threads/juce_ScopedLock.h" //============================================================================== -ActionBroadcaster::ActionBroadcaster() throw() +// special message of our own with a string in it +class ActionMessage : public Message +{ +public: + const String message; + + ActionMessage (const String& messageText, ActionListener* const listener_) throw() + : message (messageText) + { + pointerParameter = listener_; + } + +private: + ActionMessage (const ActionMessage&); + ActionMessage& operator= (const ActionMessage&); +}; + +ActionBroadcaster::CallbackReceiver::CallbackReceiver() {} + +void ActionBroadcaster::CallbackReceiver::handleMessage (const Message& message) +{ + const ActionMessage& am = static_cast (message); + ActionListener* const target = static_cast (am.pointerParameter); + + if (owner->actionListeners.contains (target)) + target->actionListenerCallback (am.message); +} + +//============================================================================== +ActionBroadcaster::ActionBroadcaster() { // are you trying to create this object before or after juce has been intialised?? jassert (MessageManager::instance != 0); + + callback.owner = this; } ActionBroadcaster::~ActionBroadcaster() @@ -46,25 +78,31 @@ ActionBroadcaster::~ActionBroadcaster() void ActionBroadcaster::addActionListener (ActionListener* const listener) { - actionListenerList.addActionListener (listener); + const ScopedLock sl (actionListenerLock); + + if (listener != 0) + actionListeners.add (listener); } void ActionBroadcaster::removeActionListener (ActionListener* const listener) { - jassert (actionListenerList.isValidMessageListener()); - - if (actionListenerList.isValidMessageListener()) - actionListenerList.removeActionListener (listener); + const ScopedLock sl (actionListenerLock); + actionListeners.removeValue (listener); } void ActionBroadcaster::removeAllActionListeners() { - actionListenerList.removeAllActionListeners(); + const ScopedLock sl (actionListenerLock); + actionListeners.clear(); } void ActionBroadcaster::sendActionMessage (const String& message) const { - actionListenerList.sendActionMessage (message); + const ScopedLock sl (actionListenerLock); + + for (int i = actionListeners.size(); --i >= 0;) + callback.postMessage (new ActionMessage (message, actionListeners.getUnchecked(i))); } + END_JUCE_NAMESPACE diff --git a/src/events/juce_ActionBroadcaster.h b/src/events/juce_ActionBroadcaster.h index b52467f3f1..6ff0dbda7e 100644 --- a/src/events/juce_ActionBroadcaster.h +++ b/src/events/juce_ActionBroadcaster.h @@ -26,7 +26,9 @@ #ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__ #define __JUCE_ACTIONBROADCASTER_JUCEHEADER__ -#include "juce_ActionListenerList.h" +#include "juce_ActionListener.h" +#include "juce_MessageListener.h" +#include "../containers/juce_SortedSet.h" //============================================================================== @@ -35,27 +37,25 @@ To quickly add methods to your class that can add/remove action listeners and broadcast to them, you can derive from this. - @see ActionListenerList, ActionListener + @see ActionListener, ChangeListener */ class JUCE_API ActionBroadcaster { public: //============================================================================== /** Creates an ActionBroadcaster. */ - ActionBroadcaster() throw(); + ActionBroadcaster(); /** Destructor. */ virtual ~ActionBroadcaster(); //============================================================================== /** Adds a listener to the list. - - (Trying to add a listener that's already on the list will have no effect). + Trying to add a listener that's already on the list will have no effect. */ void addActionListener (ActionListener* listener); /** Removes a listener from the list. - If the listener isn't on the list, this won't have any effect. */ void removeActionListener (ActionListener* listener); @@ -65,15 +65,26 @@ public: //============================================================================== /** Broadcasts a message to all the registered listeners. - - @see ActionListenerList::sendActionMessage + @see ActionListener::actionListenerCallback */ void sendActionMessage (const String& message) const; private: //============================================================================== - ActionListenerList actionListenerList; + class CallbackReceiver : public MessageListener + { + public: + CallbackReceiver(); + void handleMessage (const Message&); + + ActionBroadcaster* owner; + }; + + friend class CallbackReceiver; + CallbackReceiver callback; + SortedSet actionListeners; + CriticalSection actionListenerLock; ActionBroadcaster (const ActionBroadcaster&); ActionBroadcaster& operator= (const ActionBroadcaster&); diff --git a/src/events/juce_ActionListener.h b/src/events/juce_ActionListener.h index e6a6fda10a..9a6497b794 100644 --- a/src/events/juce_ActionListener.h +++ b/src/events/juce_ActionListener.h @@ -36,7 +36,7 @@ Used by various classes, e.g. buttons when they are pressed, to tell listeners about something that's happened. - @see ActionListenerList, ActionBroadcaster, ChangeListener + @see ActionBroadcaster, ChangeListener */ class JUCE_API ActionListener { @@ -47,7 +47,7 @@ public: /** Overridden by your subclass to receive the callback. @param message the string that was specified when the event was triggered - by a call to ActionListenerList::sendActionMessage() + by a call to ActionBroadcaster::sendActionMessage() */ virtual void actionListenerCallback (const String& message) = 0; }; diff --git a/src/events/juce_ActionListenerList.cpp b/src/events/juce_ActionListenerList.cpp deleted file mode 100644 index 7f562933f0..0000000000 --- a/src/events/juce_ActionListenerList.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-10 by Raw Material Software Ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the GNU General - Public License (Version 2), as published by the Free Software Foundation. - A copy of the license is included in the JUCE distribution, or can be found - online at www.gnu.org/licenses. - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.rawmaterialsoftware.com/juce for more information. - - ============================================================================== -*/ - -#include "../core/juce_StandardHeader.h" - -BEGIN_JUCE_NAMESPACE - -#include "juce_ActionListenerList.h" -#include "../threads/juce_ScopedLock.h" - - -//============================================================================== -// special message of our own with a string in it -class ActionMessage : public Message -{ -public: - const String message; - - ActionMessage (const String& messageText, void* const listener_) throw() - : message (messageText) - { - pointerParameter = listener_; - } - - ~ActionMessage() throw() - { - } - - -private: - ActionMessage (const ActionMessage&); - ActionMessage& operator= (const ActionMessage&); -}; - -//============================================================================== -ActionListenerList::ActionListenerList() -{ -} - -ActionListenerList::~ActionListenerList() -{ -} - -void ActionListenerList::addActionListener (ActionListener* const listener) -{ - const ScopedLock sl (actionListenerLock_); - - jassert (listener != 0); - jassert (! actionListeners_.contains (listener)); // trying to add a listener to the list twice! - - if (listener != 0) - actionListeners_.add (listener); -} - -void ActionListenerList::removeActionListener (ActionListener* const listener) -{ - const ScopedLock sl (actionListenerLock_); - - jassert (actionListeners_.contains (listener)); // trying to remove a listener that isn't on the list! - - actionListeners_.removeValue (listener); -} - -void ActionListenerList::removeAllActionListeners() -{ - const ScopedLock sl (actionListenerLock_); - actionListeners_.clear(); -} - -void ActionListenerList::sendActionMessage (const String& message) const -{ - const ScopedLock sl (actionListenerLock_); - - for (int i = actionListeners_.size(); --i >= 0;) - postMessage (new ActionMessage (message, static_cast (actionListeners_.getUnchecked(i)))); -} - -void ActionListenerList::handleMessage (const Message& message) -{ - const ActionMessage& am = (const ActionMessage&) message; - - if (actionListeners_.contains (am.pointerParameter)) - static_cast (am.pointerParameter)->actionListenerCallback (am.message); -} - -END_JUCE_NAMESPACE diff --git a/src/events/juce_ActionListenerList.h b/src/events/juce_ActionListenerList.h deleted file mode 100644 index e831d50801..0000000000 --- a/src/events/juce_ActionListenerList.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-10 by Raw Material Software Ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the GNU General - Public License (Version 2), as published by the Free Software Foundation. - A copy of the license is included in the JUCE distribution, or can be found - online at www.gnu.org/licenses. - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.rawmaterialsoftware.com/juce for more information. - - ============================================================================== -*/ - -#ifndef __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ -#define __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ - -#include "juce_ActionListener.h" -#include "juce_MessageListener.h" -#include "../containers/juce_SortedSet.h" -#include "../threads/juce_CriticalSection.h" - - -//============================================================================== -/** - A set of ActionListeners. - - Listeners can be added and removed from the list, and messages can be - broadcast to all the listeners. - - @see ActionListener, ActionBroadcaster -*/ -class JUCE_API ActionListenerList : public MessageListener -{ -public: - //============================================================================== - /** Creates an empty list. */ - ActionListenerList(); - - /** Destructor. */ - ~ActionListenerList(); - - //============================================================================== - /** Adds a listener to the list. - - (Trying to add a listener that's already on the list will have no effect). - */ - void addActionListener (ActionListener* listener); - - /** Removes a listener from the list. - - If the listener isn't on the list, this won't have any effect. - */ - void removeActionListener (ActionListener* listener); - - /** Removes all listeners from the list. */ - void removeAllActionListeners(); - - /** Broadcasts a message to all the registered listeners. - - This sends the message asynchronously. - - If a listener is on the list when this method is called but is removed from - the list before the message arrives, it won't receive the message. Similarly - listeners that are added to the list after the message is sent but before it - arrives won't get the message either. - */ - void sendActionMessage (const String& message) const; - - //============================================================================== - /** @internal */ - void handleMessage (const Message&); - - juce_UseDebuggingNewOperator - -private: - SortedSet actionListeners_; - CriticalSection actionListenerLock_; - - ActionListenerList (const ActionListenerList&); - ActionListenerList& operator= (const ActionListenerList&); -}; - - -#endif // __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ diff --git a/src/events/juce_AsyncUpdater.cpp b/src/events/juce_AsyncUpdater.cpp index e5f6475bce..9d3bf49dc1 100644 --- a/src/events/juce_AsyncUpdater.cpp +++ b/src/events/juce_AsyncUpdater.cpp @@ -28,45 +28,73 @@ BEGIN_JUCE_NAMESPACE #include "juce_AsyncUpdater.h" +#include "juce_CallbackMessage.h" +#include "../containers/juce_ScopedPointer.h" +#include "juce_MessageManager.h" +//============================================================================== +class AsyncUpdater::AsyncUpdaterMessage : public CallbackMessage +{ +public: + AsyncUpdaterMessage (AsyncUpdater& owner_) + : owner (owner_) + { + } + + void messageCallback() + { + if (owner.pendingMessage.compareAndSetBool (0, this)) + owner.handleAsyncUpdate(); + } + + AsyncUpdater& owner; +}; + //============================================================================== AsyncUpdater::AsyncUpdater() throw() - : asyncMessagePending (false) { - internalAsyncHandler.owner = this; } AsyncUpdater::~AsyncUpdater() { + // You're deleting this object with a background thread while there's an update + // pending on the main event thread - that's pretty dodgy threading, as the callback could + // happen after this destructor has finished. You should either use a MessageManagerLock while + // deleting this object, or find some other way to avoid such a race condition. + jassert (/*(! isUpdatePending()) ||*/ MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + + pendingMessage = 0; } void AsyncUpdater::triggerAsyncUpdate() { - if (! asyncMessagePending) + if (pendingMessage.value == 0) { - asyncMessagePending = true; - internalAsyncHandler.postMessage (new Message()); + ScopedPointer pending (new AsyncUpdaterMessage (*this)); + + if (pendingMessage.compareAndSetBool (pending, 0)) + pending.release()->post(); } } void AsyncUpdater::cancelPendingUpdate() throw() { - asyncMessagePending = false; + pendingMessage = 0; } void AsyncUpdater::handleUpdateNowIfNeeded() { - if (asyncMessagePending) - { - asyncMessagePending = false; + // This can only be called by the event thread. + jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + + if (pendingMessage.exchange (0) != 0) handleAsyncUpdate(); - } } -void AsyncUpdater::AsyncUpdaterInternal::handleMessage (const Message&) +bool AsyncUpdater::isUpdatePending() const throw() { - owner->handleUpdateNowIfNeeded(); + return pendingMessage.value != 0; } diff --git a/src/events/juce_AsyncUpdater.h b/src/events/juce_AsyncUpdater.h index 5500acea90..2b108bbe37 100644 --- a/src/events/juce_AsyncUpdater.h +++ b/src/events/juce_AsyncUpdater.h @@ -26,7 +26,7 @@ #ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ #define __JUCE_ASYNCUPDATER_JUCEHEADER__ -#include "juce_MessageListener.h" +#include "../core/juce_Atomic.h" //============================================================================== @@ -79,9 +79,15 @@ public: Use this as a kind of "flush" operation - if an update is pending, the handleAsyncUpdate() method will be called immediately; if no update is pending, then nothing will be done. + + Because this may invoke the callback, this method must only be called on + the main event thread. */ void handleUpdateNowIfNeeded(); + /** Returns true if there's an update callback in the pipeline. */ + bool isUpdatePending() const throw(); + //============================================================================== /** Called back to do whatever your class needs to do. @@ -93,23 +99,10 @@ public: private: //============================================================================== - class AsyncUpdaterInternal : public MessageListener - { - public: - AsyncUpdaterInternal() {} - ~AsyncUpdaterInternal() {} - - void handleMessage (const Message&); - - AsyncUpdater* owner; - - private: - AsyncUpdaterInternal (const AsyncUpdaterInternal&); - AsyncUpdaterInternal& operator= (const AsyncUpdaterInternal&); - }; + class AsyncUpdaterMessage; + friend class AsyncUpdaterMessage; - AsyncUpdaterInternal internalAsyncHandler; - bool asyncMessagePending; + Atomic pendingMessage; }; diff --git a/src/events/juce_ChangeBroadcaster.cpp b/src/events/juce_ChangeBroadcaster.cpp index 551919ac33..88d1d3e38c 100644 --- a/src/events/juce_ChangeBroadcaster.cpp +++ b/src/events/juce_ChangeBroadcaster.cpp @@ -31,42 +31,25 @@ BEGIN_JUCE_NAMESPACE #include "juce_MessageManager.h" -//============================================================================== -class ChangeBroadcaster::ChangeBroadcasterMessage : public CallbackMessage -{ -public: - ChangeBroadcasterMessage (ChangeBroadcaster* const owner_) - : owner (owner_) - { - } - - void messageCallback() - { - if (owner != 0 && owner->pendingMessage.value == this) - owner->sendSynchronousChangeMessage(); - } - - ChangeBroadcaster* owner; -}; - //============================================================================== ChangeBroadcaster::ChangeBroadcaster() throw() { // are you trying to create this object before or after juce has been intialised?? jassert (MessageManager::instance != 0); + + callback.owner = this; } ChangeBroadcaster::~ChangeBroadcaster() { // all event-based objects must be deleted BEFORE juce is shut down! jassert (MessageManager::instance != 0); - - invalidatePendingMessage(); } void ChangeBroadcaster::addChangeListener (ChangeListener* const listener) { - // Listeners can only be safely added when the event thread is locked... + // Listeners can only be safely added when the event thread is locked + // You can use a MessageManagerLock if you need to call this from another thread. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); changeListeners.add (listener); @@ -74,7 +57,8 @@ void ChangeBroadcaster::addChangeListener (ChangeListener* const listener) void ChangeBroadcaster::removeChangeListener (ChangeListener* const listener) { - // Listeners can only be safely added when the event thread is locked... + // Listeners can only be safely added when the event thread is locked + // You can use a MessageManagerLock if you need to call this from another thread. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); changeListeners.remove (listener); @@ -82,28 +66,17 @@ void ChangeBroadcaster::removeChangeListener (ChangeListener* const listener) void ChangeBroadcaster::removeAllChangeListeners() { - // Listeners can only be safely added when the event thread is locked... + // Listeners can only be safely added when the event thread is locked + // You can use a MessageManagerLock if you need to call this from another thread. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); changeListeners.clear(); } -void ChangeBroadcaster::invalidatePendingMessage() -{ - ChangeBroadcasterMessage* const oldMessage = pendingMessage.exchange (0); - if (oldMessage != 0) - oldMessage->owner = 0; -} - void ChangeBroadcaster::sendChangeMessage() { - if (pendingMessage.value == 0 && changeListeners.size() > 0) - { - ScopedPointer pending (new ChangeBroadcasterMessage (this)); - - if (pendingMessage.compareAndSetBool (pending, 0)) - pending.release()->post(); - } + if (changeListeners.size() > 0) + callback.triggerAsyncUpdate(); } void ChangeBroadcaster::sendSynchronousChangeMessage() @@ -111,14 +84,30 @@ void ChangeBroadcaster::sendSynchronousChangeMessage() // This can only be called by the event thread. jassert (MessageManager::getInstance()->isThisTheMessageThread()); - invalidatePendingMessage(); - changeListeners.call (&ChangeListener::changeListenerCallback, this); + callback.cancelPendingUpdate(); + callListeners(); } void ChangeBroadcaster::dispatchPendingMessages() { - if (pendingMessage.get() != 0) - sendSynchronousChangeMessage(); + callback.handleUpdateNowIfNeeded(); +} + +void ChangeBroadcaster::callListeners() +{ + changeListeners.call (&ChangeListener::changeListenerCallback, this); +} + +//============================================================================== +ChangeBroadcaster::ChangeBroadcasterCallback::ChangeBroadcasterCallback() + : owner (0) +{ +} + +void ChangeBroadcaster::ChangeBroadcasterCallback::handleAsyncUpdate() +{ + jassert (owner != 0); + owner->callListeners(); } diff --git a/src/events/juce_ChangeBroadcaster.h b/src/events/juce_ChangeBroadcaster.h index 72333874d8..8c6399040b 100644 --- a/src/events/juce_ChangeBroadcaster.h +++ b/src/events/juce_ChangeBroadcaster.h @@ -28,7 +28,7 @@ #include "juce_ChangeListener.h" #include "juce_ListenerList.h" -#include "../core/juce_Atomic.h" +#include "juce_AsyncUpdater.h" //============================================================================== @@ -88,13 +88,20 @@ public: private: //============================================================================== - class ChangeBroadcasterMessage; - friend class ChangeBroadcasterMessage; + class ChangeBroadcasterCallback : public AsyncUpdater + { + public: + ChangeBroadcasterCallback(); + void handleAsyncUpdate(); - Atomic pendingMessage; + ChangeBroadcaster* owner; + }; + + friend class ChangeBroadcasterCallback; + ChangeBroadcasterCallback callback; ListenerList changeListeners; - void invalidatePendingMessage(); + void callListeners(); ChangeBroadcaster (const ChangeBroadcaster&); ChangeBroadcaster& operator= (const ChangeBroadcaster&); diff --git a/src/events/juce_Message.cpp b/src/events/juce_Message.cpp index 8f51d495a3..9496ed7a03 100644 --- a/src/events/juce_Message.cpp +++ b/src/events/juce_Message.cpp @@ -35,7 +35,8 @@ Message::Message() throw() : intParameter1 (0), intParameter2 (0), intParameter3 (0), - pointerParameter (0) + pointerParameter (0), + messageRecipient (0) { } @@ -46,7 +47,8 @@ Message::Message (const int intParameter1_, : intParameter1 (intParameter1_), intParameter2 (intParameter2_), intParameter3 (intParameter3_), - pointerParameter (pointerParameter_) + pointerParameter (pointerParameter_), + messageRecipient (0) { } diff --git a/src/events/juce_MessageManager.cpp b/src/events/juce_MessageManager.cpp index 4ef0891086..77ea690925 100644 --- a/src/events/juce_MessageManager.cpp +++ b/src/events/juce_MessageManager.cpp @@ -28,7 +28,7 @@ BEGIN_JUCE_NAMESPACE #include "juce_MessageManager.h" -#include "juce_ActionListenerList.h" +#include "juce_ActionBroadcaster.h" #include "../application/juce_Application.h" #include "../gui/components/juce_Component.h" #include "../threads/juce_Thread.h" @@ -56,7 +56,7 @@ MessageManager::MessageManager() throw() MessageManager::~MessageManager() throw() { - broadcastListeners = 0; + broadcaster = 0; doPlatformSpecificShutdown(); @@ -88,48 +88,41 @@ void MessageManager::postMessageToQueue (Message* const message) } //============================================================================== -CallbackMessage::CallbackMessage() throw() {} -CallbackMessage::~CallbackMessage() {} +CallbackMessage::CallbackMessage() throw() {} +CallbackMessage::~CallbackMessage() {} void CallbackMessage::post() { if (MessageManager::instance != 0) - MessageManager::instance->postCallbackMessage (this); -} - -void MessageManager::postCallbackMessage (Message* const message) -{ - message->messageRecipient = 0; - postMessageToQueue (message); + MessageManager::instance->postMessageToQueue (this); } //============================================================================== // not for public use.. void MessageManager::deliverMessage (Message* const message) { - const ScopedPointer messageDeleter (message); - MessageListener* const recipient = message->messageRecipient; - JUCE_TRY { - if (messageListeners.contains (recipient)) - { - recipient->handleMessage (*message); - } - else if (recipient == 0) + const ScopedPointer messageDeleter (message); + MessageListener* const recipient = message->messageRecipient; + + if (recipient == 0) { - if (message->intParameter1 == quitMessageId) + CallbackMessage* const callbackMessage = dynamic_cast (message); + + if (callbackMessage != 0) { - quitMessageReceived = true; + callbackMessage->messageCallback(); } - else + else if (message->intParameter1 == quitMessageId) { - CallbackMessage* const cm = dynamic_cast (message); - - if (cm != 0) - cm->messageCallback(); + quitMessageReceived = true; } } + else if (messageListeners.contains (recipient)) + { + recipient->handleMessage (*message); + } } JUCE_CATCH_EXCEPTION } @@ -145,10 +138,7 @@ void MessageManager::runDispatchLoop() void MessageManager::stopDispatchLoop() { - Message* const m = new Message (quitMessageId, 0, 0, 0); - m->messageRecipient = 0; - postMessageToQueue (m); - + postMessageToQueue (new Message (quitMessageId, 0, 0, 0)); quitMessagePosted = true; } @@ -182,22 +172,22 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) //============================================================================== void MessageManager::deliverBroadcastMessage (const String& value) { - if (broadcastListeners != 0) - broadcastListeners->sendActionMessage (value); + if (broadcaster != 0) + broadcaster->sendActionMessage (value); } void MessageManager::registerBroadcastListener (ActionListener* const listener) { - if (broadcastListeners == 0) - broadcastListeners = new ActionListenerList(); + if (broadcaster == 0) + broadcaster = new ActionBroadcaster(); - broadcastListeners->addActionListener (listener); + broadcaster->addActionListener (listener); } void MessageManager::deregisterBroadcastListener (ActionListener* const listener) { - if (broadcastListeners != 0) - broadcastListeners->removeActionListener (listener); + if (broadcaster != 0) + broadcaster->removeActionListener (listener); } //============================================================================== @@ -239,7 +229,6 @@ class MessageManagerLock::SharedEvents : public ReferenceCountedObject { public: SharedEvents() {} - ~SharedEvents() {} /* This class just holds a couple of events to communicate between the BlockingMessage and the MessageManagerLock. Because both of these objects may be deleted at any time, @@ -255,7 +244,6 @@ class MessageManagerLock::BlockingMessage : public CallbackMessage { public: BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {} - ~BlockingMessage() throw() {} void messageCallback() { diff --git a/src/events/juce_MessageManager.h b/src/events/juce_MessageManager.h index d1763fce6d..d938fdd8f0 100644 --- a/src/events/juce_MessageManager.h +++ b/src/events/juce_MessageManager.h @@ -31,7 +31,7 @@ #include "../containers/juce_ScopedPointer.h" #include "../threads/juce_Thread.h" #include "../threads/juce_ThreadPool.h" -#include "juce_ActionListenerList.h" +#include "juce_ActionBroadcaster.h" #include "juce_CallbackMessage.h" class Component; class MessageManagerLock; @@ -175,7 +175,7 @@ private: static MessageManager* instance; SortedSet messageListeners; - ScopedPointer broadcastListeners; + ScopedPointer broadcaster; friend class JUCEApplication; bool quitMessagePosted, quitMessageReceived; @@ -184,7 +184,6 @@ private: static void* exitModalLoopCallback (void*); void postMessageToQueue (Message* message); - void postCallbackMessage (Message* message); static void doPlatformSpecificInitialisation(); static void doPlatformSpecificShutdown(); @@ -317,5 +316,4 @@ private: }; - #endif // __JUCE_MESSAGEMANAGER_JUCEHEADER__ diff --git a/src/gui/components/windows/juce_ComponentPeer.h b/src/gui/components/windows/juce_ComponentPeer.h index ee74356edf..2e7219ef23 100644 --- a/src/gui/components/windows/juce_ComponentPeer.h +++ b/src/gui/components/windows/juce_ComponentPeer.h @@ -29,7 +29,6 @@ #include "../juce_Component.h" #include "../mouse/juce_MouseCursor.h" #include "../keyboard/juce_TextInputTarget.h" -#include "../../../events/juce_MessageListener.h" #include "../../../text/juce_StringArray.h" #include "../../graphics/geometry/juce_RectangleList.h" diff --git a/src/juce_app_includes.h b/src/juce_app_includes.h index 0fa9760d7f..9a7aa5213d 100644 --- a/src/juce_app_includes.h +++ b/src/juce_app_includes.h @@ -230,9 +230,6 @@ #ifndef __JUCE_ACTIONLISTENER_JUCEHEADER__ #include "events/juce_ActionListener.h" #endif -#ifndef __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ - #include "events/juce_ActionListenerList.h" -#endif #ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ #include "events/juce_AsyncUpdater.h" #endif diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index 453ac3485e..d9c2f3a025 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -388,7 +388,7 @@ namespace NumberToStringConverters else { #if JUCE_WINDOWS - #if JUCE_VC8_OR_EARLIER || JUCE_MINGW + #if JUCE_VC7_OR_EARLIER || JUCE_MINGW len = _snwprintf (buffer, numChars, L"%.9g", n); #else len = _snwprintf_s (buffer, numChars, _TRUNCATE, L"%.9g", n);