Skip to content
Permalink
Browse files

More internal message class refactoring/decoupling.

  • Loading branch information
julianstorer committed Mar 24, 2012
1 parent 31209da commit e905f520141b66ffebfe7733b03e6e9b5dc11bf9
@@ -53,15 +53,15 @@ void ActionBroadcaster::CallbackReceiver::handleMessage (const Message& message)
ActionBroadcaster::ActionBroadcaster()
{
// are you trying to create this object before or after juce has been intialised??
jassert (MessageManager::instance != nullptr);
jassert (MessageManager::getInstanceWithoutCreating() != nullptr);

callback.owner = this;
}

ActionBroadcaster::~ActionBroadcaster()
{
// all event-based objects must be deleted BEFORE juce is shut down!
jassert (MessageManager::instance != nullptr);
jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
}

void ActionBroadcaster::addActionListener (ActionListener* const listener)
@@ -26,15 +26,15 @@
ChangeBroadcaster::ChangeBroadcaster() noexcept
{
// are you trying to create this object before or after juce has been intialised??
jassert (MessageManager::instance != nullptr);
jassert (MessageManager::getInstanceWithoutCreating() != nullptr);

callback.owner = this;
}

ChangeBroadcaster::~ChangeBroadcaster()
{
// all event-based objects must be deleted BEFORE juce is shut down!
jassert (MessageManager::instance != nullptr);
jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
}

void ChangeBroadcaster::addChangeListener (ChangeListener* const listener)
@@ -26,33 +26,34 @@
#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__
#define __JUCE_CALLBACKMESSAGE_JUCEHEADER__

#include "juce_Message.h"
#include "juce_MessageManager.h"


//==============================================================================
/**
A message that calls a custom function when it gets delivered.
A message that invokes a callback method when it gets delivered.
You can use this class to fire off actions that you want to be performed later
on the message thread.
Unlike other Message objects, these don't get sent to a MessageListener, you
just call the post() method to send them, and when they arrive, your
messageCallback() method will automatically be invoked.
To use it, create a subclass of CallbackMessage which implements the messageCallback()
method, then call post() to dispatch it. The event thread will then invoke your
messageCallback() method later on, and will automatically delete the message object
afterwards.
Always create an instance of a CallbackMessage on the heap, as it will be
Always create a new instance of a CallbackMessage on the heap, as it will be
deleted automatically after the message has been delivered.
@see MessageListener, MessageManager, ActionListener, ChangeListener
@see MessageManager, MessageListener, ActionListener, ChangeListener
*/
class JUCE_API CallbackMessage : public Message
class JUCE_API CallbackMessage : public MessageManager::MessageBase
{
public:
//==============================================================================
CallbackMessage() noexcept;
CallbackMessage() noexcept {}

/** Destructor. */
~CallbackMessage();
~CallbackMessage() {}

//==============================================================================
/** Called when the message is delivered.
@@ -65,17 +66,7 @@ class JUCE_API CallbackMessage : public Message
*/
virtual void messageCallback() = 0;

/** Instead of sending this message to a MessageListener, just call this method
to post it to the event queue.
After you've called this, this object will belong to the MessageManager,
which will delete it later. So make sure you don't delete the object yourself,
call post() more than once, or call post() on a stack-based obect!
*/
void post();

private:
//==============================================================================
// Avoid the leak-detector because for plugins, the host can unload our DLL with undelivered
// messages still in the system event queue. These aren't harmful, but can cause annoying assertions.
JUCE_DECLARE_NON_COPYABLE (CallbackMessage);
@@ -27,39 +27,35 @@
#define __JUCE_MESSAGE_JUCEHEADER__

class MessageListener;
class MessageManager;


//==============================================================================
/** The base class for objects that can be delivered to a MessageListener.
/** The base class for objects that can be sent to a MessageListener.
If you want to send a message that carries some kind of custom data, just
create a subclass of Message with some appropriate member variables to hold
your data.
Always create a new instance of a Message object on the heap, as it will be
deleted automatically after the message has been delivered.
@see MessageListener, MessageManager, ActionListener, ChangeListener
*/
class JUCE_API Message : public ReferenceCountedObject
class JUCE_API Message : public MessageManager::MessageBase
{
public:
//==============================================================================
/** Creates an uninitialised message.
The class's variables will also be left uninitialised.
*/
/** Creates an uninitialised message. */
Message() noexcept;
~Message();

/** Destructor. */
virtual ~Message();

/** A typedef for pointers to messages. */
typedef ReferenceCountedObjectPtr <Message> Ptr;
typedef ReferenceCountedObjectPtr<Message> Ptr;

//==============================================================================
private:
friend class MessageListener;
friend class MessageManager;
MessageListener* messageRecipient;
WeakReference<MessageListener> recipient;
void messageCallback();

// Avoid the leak-detector because for plugins, the host can unload our DLL with undelivered
// messages still in the system event queue. These aren't harmful, but can cause annoying assertions.
@@ -23,33 +23,29 @@
==============================================================================
*/

MessageListener::MessageListener() noexcept
{
// are you trying to create a messagelistener before or after juce has been intialised??
jassert (MessageManager::instance != nullptr);
Message::Message() noexcept {}
Message::~Message() {}

if (MessageManager::instance != nullptr)
MessageManager::instance->messageListeners.add (this);
void Message::messageCallback()
{
MessageListener* const r = recipient;
if (r != nullptr)
r->handleMessage (*this);
}

MessageListener::~MessageListener()
MessageListener::MessageListener() noexcept
{
if (MessageManager::instance != nullptr)
MessageManager::instance->messageListeners.removeValue (this);
// Are you trying to create a messagelistener before or after juce has been intialised??
jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
}

void MessageListener::postMessage (Message* const message) const
MessageListener::~MessageListener()
{
message->messageRecipient = const_cast <MessageListener*> (this);

if (MessageManager::instance == nullptr)
MessageManager::getInstance();

MessageManager::instance->postMessageToQueue (message);
masterReference.clear();
}

bool MessageListener::isValidMessageListener() const noexcept
void MessageListener::postMessage (Message* const message) const
{
return MessageManager::instance != nullptr
&& MessageManager::instance->messageListeners.contains (this);
message->recipient = const_cast <MessageListener*> (this);
message->post();
}
@@ -26,7 +26,7 @@
#ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__
#define __JUCE_MESSAGELISTENER_JUCEHEADER__

#include "juce_Message.h"
#include "juce_MessageManager.h"


//==============================================================================
@@ -37,19 +37,11 @@
*/
class JUCE_API MessageListener
{
protected:
//==============================================================================
/** Creates a MessageListener. */
MessageListener() noexcept;

public:
//==============================================================================
/** Destructor.
MessageListener() noexcept;

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.
*/
/** Destructor. */
virtual ~MessageListener();

//==============================================================================
@@ -68,25 +60,15 @@ class JUCE_API MessageListener
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.
automatically by the message queue, so make sure it's
allocated on the heap, not the stack!
@see handleMessage
*/
void postMessage (Message* message) const;

//==============================================================================
/** 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 noexcept;
private:
WeakReference<MessageListener>::Master masterReference;
friend class WeakReference<MessageListener>;
};


@@ -23,22 +23,7 @@
==============================================================================
*/

Message::Message() noexcept : messageRecipient (nullptr) {}
Message::~Message() {}

//==============================================================================
CallbackMessage::CallbackMessage() noexcept {}
CallbackMessage::~CallbackMessage() {}

void CallbackMessage::post()
{
MessageManager* const mm = MessageManager::instance;
if (mm != nullptr)
mm->postMessageToQueue (this);
}

//==============================================================================
class MessageManager::QuitMessage : public CallbackMessage
class MessageManager::QuitMessage : public MessageManager::MessageBase
{
public:
QuitMessage() {}
@@ -55,8 +40,6 @@ class MessageManager::QuitMessage : public CallbackMessage
};

//==============================================================================
MessageManager* MessageManager::instance = nullptr;

MessageManager::MessageManager() noexcept
: quitMessagePosted (false),
quitMessageReceived (false),
@@ -73,13 +56,12 @@ MessageManager::~MessageManager() noexcept

doPlatformSpecificShutdown();

// If you hit this assertion, then you've probably leaked some kind of MessageListener object..
jassert (messageListeners.size() == 0);

jassert (instance == this);
instance = nullptr; // do this last in case this instance is still needed by doPlatformSpecificShutdown()
}

MessageManager* MessageManager::instance = nullptr;

MessageManager* MessageManager::getInstance()
{
if (instance == nullptr)
@@ -91,37 +73,23 @@ MessageManager* MessageManager::getInstance()
return instance;
}

void MessageManager::deleteInstance()
inline MessageManager* MessageManager::getInstanceWithoutCreating() noexcept
{
deleteAndZero (instance);
return instance;
}

void MessageManager::postMessageToQueue (Message* const message)
void MessageManager::deleteInstance()
{
if (quitMessagePosted || ! postMessageToSystemQueue (message))
Message::Ptr deleter (message); // (this will delete messages that were just created with a 0 ref count)
deleteAndZero (instance);
}

//==============================================================================
void MessageManager::deliverMessage (Message* const message)
void MessageManager::MessageBase::post()
{
JUCE_TRY
{
MessageListener* const recipient = message->messageRecipient;

if (recipient == nullptr)
{
CallbackMessage* const callbackMessage = dynamic_cast <CallbackMessage*> (message);
MessageManager* const mm = MessageManager::instance;

if (callbackMessage != nullptr)
callbackMessage->messageCallback();
}
else if (messageListeners.contains (recipient))
{
recipient->handleMessage (*message);
}
}
JUCE_CATCH_EXCEPTION
if (mm == nullptr || mm->quitMessagePosted || ! postMessageToSystemQueue (this))
Ptr deleter (this); // (this will delete messages that were just created with a 0 ref count)
}

//==============================================================================
@@ -166,7 +134,7 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
#endif

//==============================================================================
class AsyncFunctionCallback : public CallbackMessage
class AsyncFunctionCallback : public MessageManager::MessageBase
{
public:
AsyncFunctionCallback (MessageCallbackFunction* const f, void* const param)
@@ -258,10 +226,10 @@ bool MessageManager::currentThreadHasLockedMessageManager() const noexcept
accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
in Cocoa).
*/
class MessageManagerLock::BlockingMessage : public CallbackMessage
class MessageManagerLock::BlockingMessage : public MessageManager::MessageBase
{
public:
BlockingMessage() {}
BlockingMessage() noexcept {}

void messageCallback()
{

0 comments on commit e905f52

Please sign in to comment.
You can’t perform that action at this time.