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