1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-07 04:10:08 +00:00

Rewrote MessageManagerLock (again), hopefully now making it bulletproof. Also gave it an extra constructor and changed the threads section of the juce demo to use messagemanagerlocks to animate its components. Stopped using NSLog on the mac because it's unsafe for non-literal strings. Added a bodge to fake italic fonts on the mac if a real italic is unavailable. Added a new class: CallbackMessage, for triggering a custom callback on the event thread. Updated the RTAS plugin build to use the 8.0 version of the SDK. Fixed a problem with ComponentDraggers when working inside a magnifier component.

This commit is contained in:
jules 2009-03-07 12:02:32 +00:00
parent 975851d31c
commit 540474d0ce
41 changed files with 2430 additions and 2095 deletions

View file

@ -38,6 +38,7 @@ BEGIN_JUCE_NAMESPACE
#include "../application/juce_Application.h"
#include "../gui/components/juce_Component.h"
#include "../../juce_core/threads/juce_Thread.h"
#include "../../juce_core/threads/juce_ScopedLock.h"
#include "../../juce_core/basics/juce_Time.h"
@ -46,7 +47,6 @@ BEGIN_JUCE_NAMESPACE
bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
bool juce_postMessageToSystemQueue (void* message);
//==============================================================================
MessageManager* MessageManager::instance = 0;
@ -55,9 +55,9 @@ static const int quitMessageId = 0xfffff321;
MessageManager::MessageManager() throw()
: broadcastListeners (0),
quitMessagePosted (false),
quitMessageReceived (false)
quitMessageReceived (false),
threadWithLock (0)
{
currentLockingThreadId = 0;
messageThreadId = Thread::getCurrentThreadId();
}
@ -88,27 +88,48 @@ void MessageManager::postMessageToQueue (Message* const message)
delete message;
}
//==============================================================================
CallbackMessage::CallbackMessage() throw() {}
CallbackMessage::~CallbackMessage() throw() {}
void CallbackMessage::post()
{
if (MessageManager::instance != 0)
MessageManager::instance->postCallbackMessage (this);
}
void MessageManager::postCallbackMessage (Message* const message)
{
message->messageRecipient = 0;
postMessageToQueue (message);
}
//==============================================================================
// not for public use..
void MessageManager::deliverMessage (void* message)
{
const MessageManagerLock lock;
Message* const m = (Message*) message;
MessageListener* const recipient = m->messageRecipient;
if (messageListeners.contains (recipient))
JUCE_TRY
{
JUCE_TRY
if (messageListeners.contains (recipient))
{
recipient->handleMessage (*m);
}
JUCE_CATCH_EXCEPTION
}
else if (recipient == 0 && m->intParameter1 == quitMessageId)
{
quitMessageReceived = true;
else if (recipient == 0)
{
if (m->intParameter1 == quitMessageId)
{
quitMessageReceived = true;
}
else if (dynamic_cast <CallbackMessage*> (m) != 0)
{
(dynamic_cast <CallbackMessage*> (m))->messageCallback();
}
}
}
JUCE_CATCH_EXCEPTION
delete m;
}
@ -186,54 +207,135 @@ void MessageManager::setCurrentMessageThread (const Thread::ThreadID threadId) t
bool MessageManager::currentThreadHasLockedMessageManager() const throw()
{
return Thread::getCurrentThreadId() == currentLockingThreadId;
const Thread::ThreadID thisThread = Thread::getCurrentThreadId();
return thisThread == messageThreadId || thisThread == threadWithLock;
}
//==============================================================================
MessageManagerLock::MessageManagerLock() throw()
: lastLockingThreadId (0),
locked (false)
//==============================================================================
/* The only safe way to lock the message thread while another thread does
some work is by posting a special message, whose purpose is to tie up the event
loop until the other thread has finished its business.
Any other approach can get horribly deadlocked if the OS uses its own hidden locks which
get locked before making an event callback, because if the same OS lock gets indirectly
accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
in Cocoa).
*/
class SharedLockingEvents : public ReferenceCountedObject
{
if (MessageManager::instance != 0)
public:
SharedLockingEvents() throw() {}
~SharedLockingEvents() {}
/* This class just holds a couple of events to communicate between the MMLockMessage
and the MessageManagerLock. Because both of these objects may be deleted at any time,
this shared data must be kept in a separate, ref-counted container. */
WaitableEvent lockedEvent, releaseEvent;
};
class MMLockMessage : public CallbackMessage
{
public:
MMLockMessage (SharedLockingEvents* const events_) throw()
: events (events_)
{}
~MMLockMessage() throw() {}
ReferenceCountedObjectPtr <SharedLockingEvents> events;
void messageCallback()
{
MessageManager::instance->messageDispatchLock.enter();
lastLockingThreadId = MessageManager::instance->currentLockingThreadId;
MessageManager::instance->currentLockingThreadId = Thread::getCurrentThreadId();
locked = true;
events->lockedEvent.signal();
events->releaseEvent.wait();
}
juce_UseDebuggingNewOperator
MMLockMessage (const MMLockMessage&);
const MMLockMessage& operator= (const MMLockMessage&);
};
//==============================================================================
MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) throw()
: locked (false),
needsUnlocking (false)
{
init (threadToCheck, 0);
}
MessageManagerLock::MessageManagerLock (Thread* const thread) throw()
: locked (false)
MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) throw()
: locked (false),
needsUnlocking (false)
{
jassert (thread != 0); // This will only work if you give it a valid thread!
init (0, jobToCheckForExitSignal);
}
void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const job) throw()
{
if (MessageManager::instance != 0)
{
for (;;)
if (MessageManager::instance->currentThreadHasLockedMessageManager())
{
if (MessageManager::instance->messageDispatchLock.tryEnter())
locked = true; // either we're on the message thread, or this it's a re-entrant call.
}
else
{
if (threadToCheck == 0 && job == 0)
{
locked = true;
lastLockingThreadId = MessageManager::instance->currentLockingThreadId;
MessageManager::instance->currentLockingThreadId = Thread::getCurrentThreadId();
break;
MessageManager::instance->lockingLock.enter();
}
else
{
while (! MessageManager::instance->lockingLock.tryEnter())
{
if ((threadToCheck != 0 && threadToCheck->threadShouldExit())
|| (job != 0 && job->shouldExit()))
return;
Thread::sleep (1);
}
}
if (thread != 0 && thread->threadShouldExit())
break;
SharedLockingEvents* const events = new SharedLockingEvents();
sharedEvents = events;
events->incReferenceCount();
Thread::sleep (1);
(new MMLockMessage (events))->post();
while (! events->lockedEvent.wait (50))
{
if ((threadToCheck != 0 && threadToCheck->threadShouldExit())
|| (job != 0 && job->shouldExit()))
{
events->releaseEvent.signal();
events->decReferenceCount();
MessageManager::instance->lockingLock.exit();
return;
}
}
jassert (MessageManager::instance->threadWithLock == 0);
MessageManager::instance->threadWithLock = Thread::getCurrentThreadId();
locked = true;
needsUnlocking = true;
}
}
}
MessageManagerLock::~MessageManagerLock() throw()
{
if (locked && MessageManager::instance != 0)
if (needsUnlocking && MessageManager::instance != 0)
{
MessageManager::instance->currentLockingThreadId = lastLockingThreadId;
MessageManager::instance->messageDispatchLock.exit();
jassert (MessageManager::instance->currentThreadHasLockedMessageManager());
((SharedLockingEvents*) sharedEvents)->releaseEvent.signal();
((SharedLockingEvents*) sharedEvents)->decReferenceCount();
MessageManager::instance->threadWithLock = 0;
MessageManager::instance->lockingLock.exit();
}
}