mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-13 00:04:19 +00:00
Changed the Message class to be reference-counted, and used this to tighten up some messaging code. Minor tweaks to AudioThumbnail, ReferenceCountedArray.
This commit is contained in:
parent
1a887cda63
commit
d60f661789
22 changed files with 573 additions and 527 deletions
|
|
@ -21666,7 +21666,7 @@ public:
|
|||
void setThumbnail (AudioThumbnail* thumb)
|
||||
{
|
||||
if (thumb != 0)
|
||||
thumb->reset (buffer.getNumChannels(), writer->getSampleRate());
|
||||
thumb->reset (buffer.getNumChannels(), writer->getSampleRate(), 0);
|
||||
|
||||
const ScopedLock sl (thumbnailLock);
|
||||
thumbnailToUpdate = thumb;
|
||||
|
|
@ -22475,14 +22475,15 @@ void AudioThumbnail::clear()
|
|||
sendChangeMessage();
|
||||
}
|
||||
|
||||
void AudioThumbnail::reset (int newNumChannels, double newSampleRate)
|
||||
void AudioThumbnail::reset (int newNumChannels, double newSampleRate, int64 totalSamplesInSource)
|
||||
{
|
||||
clear();
|
||||
|
||||
numChannels = newNumChannels;
|
||||
sampleRate = newSampleRate;
|
||||
totalSamples = totalSamplesInSource;
|
||||
|
||||
createChannels (0);
|
||||
createChannels (1 + (int) (totalSamplesInSource / samplesPerThumbSample));
|
||||
}
|
||||
|
||||
void AudioThumbnail::createChannels (const int length)
|
||||
|
|
@ -38416,28 +38417,34 @@ END_JUCE_NAMESPACE
|
|||
/*** Start of inlined file: juce_AsyncUpdater.cpp ***/
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
class AsyncUpdater::AsyncUpdaterMessage : public CallbackMessage
|
||||
class AsyncUpdaterMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
AsyncUpdaterMessage (AsyncUpdater& owner_)
|
||||
: owner (owner_)
|
||||
{
|
||||
setMessageIsDeletedOnDelivery (false);
|
||||
}
|
||||
|
||||
void messageCallback()
|
||||
{
|
||||
if (owner.pendingMessage.compareAndSetBool (0, this))
|
||||
if (shouldDeliver.compareAndSetBool (0, 1))
|
||||
owner.handleAsyncUpdate();
|
||||
}
|
||||
|
||||
Atomic<int> shouldDeliver;
|
||||
|
||||
private:
|
||||
AsyncUpdater& owner;
|
||||
};
|
||||
|
||||
AsyncUpdater::AsyncUpdater()
|
||||
: message (new AsyncUpdaterMessage (*this))
|
||||
{
|
||||
message = new AsyncUpdaterMessage (*this);
|
||||
}
|
||||
|
||||
inline Atomic<int>& AsyncUpdater::getDeliveryFlag() const throw()
|
||||
{
|
||||
return static_cast <AsyncUpdaterMessage*> (message.getObject())->shouldDeliver;
|
||||
}
|
||||
|
||||
AsyncUpdater::~AsyncUpdater()
|
||||
|
|
@ -38448,19 +38455,18 @@ AsyncUpdater::~AsyncUpdater()
|
|||
// deleting this object, or find some other way to avoid such a race condition.
|
||||
jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager());
|
||||
|
||||
if (pendingMessage.exchange (0) != 0)
|
||||
message.release()->setMessageIsDeletedOnDelivery (true);
|
||||
getDeliveryFlag().set (0);
|
||||
}
|
||||
|
||||
void AsyncUpdater::triggerAsyncUpdate()
|
||||
{
|
||||
if (pendingMessage.compareAndSetBool (message, 0))
|
||||
if (getDeliveryFlag().compareAndSetBool (1, 0))
|
||||
message->post();
|
||||
}
|
||||
|
||||
void AsyncUpdater::cancelPendingUpdate() throw()
|
||||
{
|
||||
pendingMessage = 0;
|
||||
getDeliveryFlag().set (0);
|
||||
}
|
||||
|
||||
void AsyncUpdater::handleUpdateNowIfNeeded()
|
||||
|
|
@ -38468,13 +38474,13 @@ void AsyncUpdater::handleUpdateNowIfNeeded()
|
|||
// This can only be called by the event thread.
|
||||
jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
|
||||
|
||||
if (pendingMessage.exchange (0) != 0)
|
||||
if (getDeliveryFlag().exchange (0) != 0)
|
||||
handleAsyncUpdate();
|
||||
}
|
||||
|
||||
bool AsyncUpdater::isUpdatePending() const throw()
|
||||
{
|
||||
return pendingMessage.value != 0;
|
||||
return getDeliveryFlag().value != 0;
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
@ -39088,10 +39094,10 @@ MessageManager* MessageManager::getInstance() throw()
|
|||
void MessageManager::postMessageToQueue (Message* const message)
|
||||
{
|
||||
if (quitMessagePosted || ! juce_postMessageToSystemQueue (message))
|
||||
delete message;
|
||||
Message::Ptr deleter (message); // (this will delete messages that were just created with a 0 ref count)
|
||||
}
|
||||
|
||||
CallbackMessage::CallbackMessage() throw() : deleteOnDelivery (true) {}
|
||||
CallbackMessage::CallbackMessage() throw() {}
|
||||
CallbackMessage::~CallbackMessage() {}
|
||||
|
||||
void CallbackMessage::post()
|
||||
|
|
@ -39105,7 +39111,6 @@ void MessageManager::deliverMessage (Message* const message)
|
|||
{
|
||||
JUCE_TRY
|
||||
{
|
||||
ScopedPointer <Message> messageDeleter (message);
|
||||
MessageListener* const recipient = message->messageRecipient;
|
||||
|
||||
if (recipient == 0)
|
||||
|
|
@ -39115,9 +39120,6 @@ void MessageManager::deliverMessage (Message* const message)
|
|||
if (callbackMessage != 0)
|
||||
{
|
||||
callbackMessage->messageCallback();
|
||||
|
||||
if (! callbackMessage->isMessageDeletedOnDelivery())
|
||||
messageDeleter.release();
|
||||
}
|
||||
else if (message->intParameter1 == quitMessageId)
|
||||
{
|
||||
|
|
@ -39200,9 +39202,11 @@ bool MessageManager::isThisTheMessageThread() const throw()
|
|||
|
||||
void MessageManager::setCurrentThreadAsMessageThread()
|
||||
{
|
||||
if (messageThreadId != Thread::getCurrentThreadId())
|
||||
const Thread::ThreadID thisThread = Thread::getCurrentThreadId();
|
||||
|
||||
if (messageThreadId != thisThread)
|
||||
{
|
||||
messageThreadId = Thread::getCurrentThreadId();
|
||||
messageThreadId = thisThread;
|
||||
|
||||
// This is needed on windows to make sure the message window is created by this thread
|
||||
doPlatformSpecificShutdown();
|
||||
|
|
@ -39225,47 +39229,31 @@ bool MessageManager::currentThreadHasLockedMessageManager() const throw()
|
|||
accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
|
||||
in Cocoa).
|
||||
*/
|
||||
class MessageManagerLock::SharedEvents : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
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,
|
||||
this shared data must be kept in a separate, ref-counted container. */
|
||||
WaitableEvent lockedEvent, releaseEvent;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE (SharedEvents);
|
||||
};
|
||||
|
||||
class MessageManagerLock::BlockingMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {}
|
||||
BlockingMessage() {}
|
||||
|
||||
void messageCallback()
|
||||
{
|
||||
events->lockedEvent.signal();
|
||||
events->releaseEvent.wait();
|
||||
lockedEvent.signal();
|
||||
releaseEvent.wait();
|
||||
}
|
||||
|
||||
private:
|
||||
ReferenceCountedObjectPtr <MessageManagerLock::SharedEvents> events;
|
||||
WaitableEvent lockedEvent, releaseEvent;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlockingMessage);
|
||||
};
|
||||
|
||||
MessageManagerLock::MessageManagerLock (Thread* const threadToCheck)
|
||||
: sharedEvents (0),
|
||||
locked (false)
|
||||
: locked (false)
|
||||
{
|
||||
init (threadToCheck, 0);
|
||||
}
|
||||
|
||||
MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal)
|
||||
: sharedEvents (0),
|
||||
locked (false)
|
||||
: locked (false)
|
||||
{
|
||||
init (0, jobToCheckForExitSignal);
|
||||
}
|
||||
|
|
@ -39296,19 +39284,16 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const
|
|||
}
|
||||
}
|
||||
|
||||
sharedEvents = new SharedEvents();
|
||||
sharedEvents->incReferenceCount();
|
||||
blockingMessage = new BlockingMessage();
|
||||
blockingMessage->post();
|
||||
|
||||
(new BlockingMessage (sharedEvents))->post();
|
||||
|
||||
while (! sharedEvents->lockedEvent.wait (50))
|
||||
while (! blockingMessage->lockedEvent.wait (20))
|
||||
{
|
||||
if ((threadToCheck != 0 && threadToCheck->threadShouldExit())
|
||||
|| (job != 0 && job->shouldExit()))
|
||||
{
|
||||
sharedEvents->releaseEvent.signal();
|
||||
sharedEvents->decReferenceCount();
|
||||
sharedEvents = 0;
|
||||
blockingMessage->releaseEvent.signal();
|
||||
blockingMessage = 0;
|
||||
MessageManager::instance->lockingLock.exit();
|
||||
return;
|
||||
}
|
||||
|
|
@ -39324,12 +39309,12 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const
|
|||
|
||||
MessageManagerLock::~MessageManagerLock() throw()
|
||||
{
|
||||
if (sharedEvents != 0)
|
||||
if (blockingMessage != 0)
|
||||
{
|
||||
jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager());
|
||||
|
||||
sharedEvents->releaseEvent.signal();
|
||||
sharedEvents->decReferenceCount();
|
||||
blockingMessage->releaseEvent.signal();
|
||||
blockingMessage = 0;
|
||||
|
||||
if (MessageManager::instance != 0)
|
||||
{
|
||||
|
|
@ -39478,6 +39463,7 @@ public:
|
|||
void run()
|
||||
{
|
||||
uint32 lastTime = Time::getMillisecondCounter();
|
||||
Message::Ptr message (new Message());
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
|
|
@ -39503,7 +39489,7 @@ public:
|
|||
*/
|
||||
if (callbackNeeded.compareAndSetBool (1, 0))
|
||||
{
|
||||
postMessage (new Message());
|
||||
postMessage (message);
|
||||
|
||||
/* Sometimes our message can get discarded by the OS (e.g. when running as an RTAS
|
||||
when the app has a modal loop), so this is how long to wait before assuming the
|
||||
|
|
@ -41290,6 +41276,10 @@ void Component::exitModalState (const int returnValue)
|
|||
}
|
||||
else
|
||||
{
|
||||
// if component methods are being called from threads other than the message
|
||||
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
|
||||
CHECK_MESSAGE_MANAGER_IS_LOCKED
|
||||
|
||||
class ExitModalStateMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
|
|
@ -41854,6 +41844,10 @@ void Component::parentSizeChanged()
|
|||
|
||||
void Component::addComponentListener (ComponentListener* const newListener)
|
||||
{
|
||||
// if component methods are being called from threads other than the message
|
||||
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
|
||||
CHECK_MESSAGE_MANAGER_IS_LOCKED
|
||||
|
||||
componentListeners.add (newListener);
|
||||
}
|
||||
|
||||
|
|
@ -41895,6 +41889,10 @@ void Component::paintOverChildren (Graphics&)
|
|||
|
||||
void Component::postCommandMessage (const int commandId)
|
||||
{
|
||||
// if component methods are being called from threads other than the message
|
||||
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
|
||||
CHECK_MESSAGE_MANAGER_IS_LOCKED
|
||||
|
||||
class CustomCommandMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
|
|
@ -239896,7 +239894,9 @@ static LRESULT CALLBACK juce_MessageWndProc (HWND h,
|
|||
// here in case there are windows modal dialog boxes doing their own
|
||||
// dispatch loop and not calling our version
|
||||
|
||||
MessageManager::getInstance()->deliverMessage ((Message*) lParam);
|
||||
Message* const message = reinterpret_cast <Message*> (lParam);
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
message->decReferenceCount();
|
||||
return 0;
|
||||
}
|
||||
else if (message == broadcastId)
|
||||
|
|
@ -239984,7 +239984,9 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
|
|||
{
|
||||
if (m.message == specialId && m.hwnd == juce_messageWindowHandle)
|
||||
{
|
||||
MessageManager::getInstance()->deliverMessage ((Message*) (void*) m.lParam);
|
||||
Message* const message = reinterpret_cast <Message*> (m.lParam);
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
message->decReferenceCount();
|
||||
}
|
||||
else if (m.message == WM_QUIT)
|
||||
{
|
||||
|
|
@ -240014,6 +240016,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
|
|||
|
||||
bool juce_postMessageToSystemQueue (Message* message)
|
||||
{
|
||||
message->incReferenceCount();
|
||||
return PostMessage (juce_messageWindowHandle, specialId, 0, (LPARAM) message) != 0;
|
||||
}
|
||||
|
||||
|
|
@ -255883,7 +255886,7 @@ public:
|
|||
|
||||
private:
|
||||
CriticalSection lock;
|
||||
OwnedArray <Message> queue;
|
||||
ReferenceCountedArray <Message> queue;
|
||||
int fd[2];
|
||||
int bytesInSocket;
|
||||
int totalEventCount;
|
||||
|
|
@ -255923,15 +255926,15 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
Message* popNextMessage()
|
||||
const Message::Ptr popNextMessage()
|
||||
{
|
||||
ScopedLock sl (lock);
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
if (bytesInSocket > 0)
|
||||
{
|
||||
--bytesInSocket;
|
||||
|
||||
ScopedUnlock ul (lock);
|
||||
const ScopedUnlock ul (lock);
|
||||
unsigned char x;
|
||||
size_t numBytes = read (fd[1], &x, 1);
|
||||
(void) numBytes;
|
||||
|
|
@ -255942,7 +255945,7 @@ private:
|
|||
|
||||
bool dispatchNextInternalMessage()
|
||||
{
|
||||
ScopedPointer <Message> msg (popNextMessage());
|
||||
const Message::Ptr msg (popNextMessage());
|
||||
|
||||
if (msg == 0)
|
||||
return false;
|
||||
|
|
@ -255958,7 +255961,7 @@ private:
|
|||
else
|
||||
{
|
||||
// Handle "normal" messages
|
||||
MessageManager::getInstance()->deliverMessage (msg.release());
|
||||
MessageManager::getInstance()->deliverMessage (msg);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -262337,6 +262340,73 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
class MessageQueue
|
||||
{
|
||||
public:
|
||||
MessageQueue()
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 && ! JUCE_IOS
|
||||
runLoop = CFRunLoopGetMain();
|
||||
#else
|
||||
runLoop = CFRunLoopGetCurrent();
|
||||
#endif
|
||||
|
||||
CFRunLoopSourceContext sourceContext;
|
||||
zerostruct (sourceContext);
|
||||
sourceContext.info = this;
|
||||
sourceContext.perform = runLoopSourceCallback;
|
||||
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
|
||||
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
}
|
||||
|
||||
~MessageQueue()
|
||||
{
|
||||
CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopSourceInvalidate (runLoopSource);
|
||||
CFRelease (runLoopSource);
|
||||
}
|
||||
|
||||
void post (Message* const message)
|
||||
{
|
||||
messages.add (message);
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
|
||||
private:
|
||||
ReferenceCountedArray <Message, CriticalSection> messages;
|
||||
CriticalSection lock;
|
||||
CFRunLoopRef runLoop;
|
||||
CFRunLoopSourceRef runLoopSource;
|
||||
|
||||
bool deliverNextMessage()
|
||||
{
|
||||
const Message::Ptr nextMessage (messages.removeAndReturn (0));
|
||||
|
||||
if (nextMessage == 0)
|
||||
return false;
|
||||
|
||||
const ScopedAutoReleasePool pool;
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
void runLoopCallback()
|
||||
{
|
||||
for (int i = 4; --i >= 0;)
|
||||
if (! deliverNextMessage())
|
||||
return;
|
||||
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
|
||||
static void runLoopSourceCallback (void* info)
|
||||
{
|
||||
static_cast <MessageQueue*> (info)->runLoopCallback();
|
||||
}
|
||||
};
|
||||
|
||||
#define JUCE_INCLUDED_FILE 1
|
||||
|
||||
// Now include the actual code files..
|
||||
|
|
@ -264281,12 +264351,12 @@ const File File::getSpecialLocation (const SpecialLocationType type)
|
|||
case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break;
|
||||
|
||||
#if JUCE_IOS
|
||||
case userDocumentsDirectory: resultPath = getIOSSystemLocation (NSDocumentDirectory); break;
|
||||
case userDesktopDirectory: resultPath = getIOSSystemLocation (NSDesktopDirectory); break;
|
||||
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
|
||||
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
File tmp (getIOSSystemLocation (NSCachesDirectory));
|
||||
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
|
||||
tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension());
|
||||
tmp.createDirectory();
|
||||
return tmp.getFullPathName();
|
||||
|
|
@ -267433,79 +267503,41 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
|
|||
return ! quitMessagePosted;
|
||||
}
|
||||
|
||||
namespace iOSMessageLoopHelpers
|
||||
struct MessageDispatchSystem
|
||||
{
|
||||
static CFRunLoopRef runLoop = 0;
|
||||
static CFRunLoopSourceRef runLoopSource = 0;
|
||||
static OwnedArray <Message, CriticalSection>* pendingMessages = 0;
|
||||
static JuceCustomMessageHandler* juceCustomMessageHandler = 0;
|
||||
|
||||
void runLoopSourceCallback (void*)
|
||||
MessageDispatchSystem()
|
||||
: juceCustomMessageHandler (0)
|
||||
{
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
int numDispatched = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Message* const nextMessage = pendingMessages->removeAndReturn (0);
|
||||
|
||||
if (nextMessage == 0)
|
||||
return;
|
||||
|
||||
const ScopedAutoReleasePool pool;
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
|
||||
} while (++numDispatched <= 4);
|
||||
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
~MessageDispatchSystem()
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler];
|
||||
[juceCustomMessageHandler release];
|
||||
}
|
||||
|
||||
JuceCustomMessageHandler* juceCustomMessageHandler;
|
||||
MessageQueue messageQueue;
|
||||
};
|
||||
|
||||
static MessageDispatchSystem* dispatcher = 0;
|
||||
|
||||
void MessageManager::doPlatformSpecificInitialisation()
|
||||
{
|
||||
using namespace iOSMessageLoopHelpers;
|
||||
pendingMessages = new OwnedArray <Message, CriticalSection>();
|
||||
|
||||
runLoop = CFRunLoopGetCurrent();
|
||||
CFRunLoopSourceContext sourceContext;
|
||||
zerostruct (sourceContext);
|
||||
sourceContext.perform = runLoopSourceCallback;
|
||||
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
|
||||
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
|
||||
if (juceCustomMessageHandler == 0)
|
||||
juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init];
|
||||
if (dispatcher == 0)
|
||||
dispatcher = new MessageDispatchSystem();
|
||||
}
|
||||
|
||||
void MessageManager::doPlatformSpecificShutdown()
|
||||
{
|
||||
using namespace iOSMessageLoopHelpers;
|
||||
CFRunLoopSourceInvalidate (runLoopSource);
|
||||
CFRelease (runLoopSource);
|
||||
runLoopSource = 0;
|
||||
deleteAndZero (pendingMessages);
|
||||
|
||||
if (juceCustomMessageHandler != 0)
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler];
|
||||
[juceCustomMessageHandler release];
|
||||
juceCustomMessageHandler = 0;
|
||||
}
|
||||
deleteAndZero (dispatcher);
|
||||
}
|
||||
|
||||
bool juce_postMessageToSystemQueue (Message* message)
|
||||
{
|
||||
using namespace iOSMessageLoopHelpers;
|
||||
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
pendingMessages->add (message);
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
if (dispatcher != 0)
|
||||
dispatcher->messageQueue.post (message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -267516,14 +267548,14 @@ void MessageManager::broadcastMessage (const String& value)
|
|||
|
||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data)
|
||||
{
|
||||
using namespace iOSMessageLoopHelpers;
|
||||
|
||||
if (isThisTheMessageThread())
|
||||
{
|
||||
return (*callback) (data);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassert (dispatcher != 0); // trying to call this when the juce system isn't initialised..
|
||||
|
||||
// If a thread has a MessageManagerLock and then tries to call this method, it'll
|
||||
// deadlock because the message manager is blocked from running, so can never
|
||||
// call your function..
|
||||
|
|
@ -267537,11 +267569,11 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* call
|
|||
cmp.result = 0;
|
||||
cmp.hasBeenExecuted = false;
|
||||
|
||||
[juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:)
|
||||
withObject: [NSData dataWithBytesNoCopy: &cmp
|
||||
length: sizeof (cmp)
|
||||
freeWhenDone: NO]
|
||||
waitUntilDone: YES];
|
||||
[dispatcher->juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:)
|
||||
withObject: [NSData dataWithBytesNoCopy: &cmp
|
||||
length: sizeof (cmp)
|
||||
freeWhenDone: NO]
|
||||
waitUntilDone: YES];
|
||||
|
||||
return cmp.result;
|
||||
}
|
||||
|
|
@ -275660,24 +275692,10 @@ class AppDelegateRedirector
|
|||
public:
|
||||
AppDelegateRedirector()
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
|
||||
runLoop = CFRunLoopGetMain();
|
||||
#else
|
||||
runLoop = CFRunLoopGetCurrent();
|
||||
#endif
|
||||
CFRunLoopSourceContext sourceContext;
|
||||
zerostruct (sourceContext);
|
||||
sourceContext.info = this;
|
||||
sourceContext.perform = runLoopSourceCallback;
|
||||
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
|
||||
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
}
|
||||
|
||||
virtual ~AppDelegateRedirector()
|
||||
{
|
||||
CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopSourceInvalidate (runLoopSource);
|
||||
CFRelease (runLoopSource);
|
||||
}
|
||||
|
||||
virtual NSApplicationTerminateReply shouldTerminate()
|
||||
|
|
@ -275753,40 +275771,13 @@ public:
|
|||
|
||||
void postMessage (Message* const m)
|
||||
{
|
||||
messages.add (m);
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
messageQueue.post (m);
|
||||
}
|
||||
|
||||
private:
|
||||
CFRunLoopRef runLoop;
|
||||
CFRunLoopSourceRef runLoopSource;
|
||||
OwnedArray <Message, CriticalSection> messages;
|
||||
|
||||
void runLoopCallback()
|
||||
{
|
||||
int numDispatched = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Message* const nextMessage = messages.removeAndReturn (0);
|
||||
|
||||
if (nextMessage == 0)
|
||||
return;
|
||||
|
||||
const ScopedAutoReleasePool pool;
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
|
||||
} while (++numDispatched <= 4);
|
||||
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
|
||||
static void runLoopSourceCallback (void* info)
|
||||
{
|
||||
static_cast <AppDelegateRedirector*> (info)->runLoopCallback();
|
||||
}
|
||||
MessageQueue messageQueue;
|
||||
};
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 52
|
||||
#define JUCE_BUILDNUMBER 106
|
||||
#define JUCE_BUILDNUMBER 107
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
@ -11025,6 +11025,7 @@ template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSec
|
|||
class ReferenceCountedArray
|
||||
{
|
||||
public:
|
||||
typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr;
|
||||
|
||||
/** Creates an empty array.
|
||||
@see ReferenceCountedObject, Array, OwnedArray
|
||||
|
|
@ -11101,7 +11102,7 @@ public:
|
|||
|
||||
@see getUnchecked
|
||||
*/
|
||||
inline const ReferenceCountedObjectPtr<ObjectClass> operator[] (const int index) const throw()
|
||||
inline const ObjectClassPtr operator[] (const int index) const throw()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
|
||||
|
|
@ -11113,7 +11114,7 @@ public:
|
|||
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||
it can be used when you're sure the index if always going to be legal.
|
||||
*/
|
||||
inline const ReferenceCountedObjectPtr<ObjectClass> getUnchecked (const int index) const throw()
|
||||
inline const ObjectClassPtr getUnchecked (const int index) const throw()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
jassert (isPositiveAndBelow (index, numUsed));
|
||||
|
|
@ -11125,7 +11126,7 @@ public:
|
|||
This will return a null pointer if the array's empty.
|
||||
@see getLast
|
||||
*/
|
||||
inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw()
|
||||
inline const ObjectClassPtr getFirst() const throw()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return numUsed > 0 ? data.elements [0]
|
||||
|
|
@ -11137,7 +11138,7 @@ public:
|
|||
This will return a null pointer if the array's empty.
|
||||
@see getFirst
|
||||
*/
|
||||
inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw()
|
||||
inline const ObjectClassPtr getLast() const throw()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return numUsed > 0 ? data.elements [numUsed - 1]
|
||||
|
|
@ -11409,6 +11410,43 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/** Removes and returns an object from the array.
|
||||
|
||||
This will remove the object at a given index and return it, moving back all
|
||||
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||
nothing will happen and a null pointer will be returned.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
const ObjectClassPtr removeAndReturn (const int indexToRemove)
|
||||
{
|
||||
ObjectClassPtr removedItem;
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||
{
|
||||
ObjectClass** const e = data.elements + indexToRemove;
|
||||
|
||||
if (*e != 0)
|
||||
{
|
||||
removedItem = *e;
|
||||
(*e)->decReferenceCount();
|
||||
}
|
||||
|
||||
--numUsed;
|
||||
const int numberToShift = numUsed - indexToRemove;
|
||||
|
||||
if (numberToShift > 0)
|
||||
memmove (e, e + 1, numberToShift * sizeof (ObjectClass*));
|
||||
|
||||
if ((numUsed << 1) < data.numAllocated)
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
return removedItem;
|
||||
}
|
||||
|
||||
/** Removes the first occurrence of a specified object from the array.
|
||||
|
||||
If the item isn't found, no action is taken. If it is found, it is
|
||||
|
|
@ -12476,6 +12514,123 @@ private:
|
|||
#ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__
|
||||
#define __JUCE_ASYNCUPDATER_JUCEHEADER__
|
||||
|
||||
|
||||
/*** Start of inlined file: juce_CallbackMessage.h ***/
|
||||
#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__
|
||||
#define __JUCE_CALLBACKMESSAGE_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 ReferenceCountedObject
|
||||
{
|
||||
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. */
|
||||
|
||||
/** A typedef for pointers to messages. */
|
||||
typedef ReferenceCountedObjectPtr <Message> Ptr;
|
||||
|
||||
private:
|
||||
friend class MessageListener;
|
||||
friend class MessageManager;
|
||||
MessageListener* messageRecipient;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message);
|
||||
};
|
||||
|
||||
#endif // __JUCE_MESSAGE_JUCEHEADER__
|
||||
/*** End of inlined file: juce_Message.h ***/
|
||||
|
||||
/**
|
||||
A message that calls a custom function 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.
|
||||
|
||||
Always create an instance of a CallbackMessage on the heap, as it will be
|
||||
deleted automatically after the message has been delivered.
|
||||
|
||||
@see MessageListener, MessageManager, ActionListener, ChangeListener
|
||||
*/
|
||||
class JUCE_API CallbackMessage : public Message
|
||||
{
|
||||
public:
|
||||
|
||||
CallbackMessage() throw();
|
||||
|
||||
/** Destructor. */
|
||||
~CallbackMessage();
|
||||
|
||||
/** Called when the message is delivered.
|
||||
|
||||
You should implement this method and make it do whatever action you want
|
||||
to perform.
|
||||
|
||||
Note that like all other messages, this object will be deleted immediately
|
||||
after this method has been invoked.
|
||||
*/
|
||||
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:
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackMessage);
|
||||
};
|
||||
|
||||
#endif // __JUCE_CALLBACKMESSAGE_JUCEHEADER__
|
||||
/*** End of inlined file: juce_CallbackMessage.h ***/
|
||||
|
||||
/**
|
||||
Has a callback method that is triggered asynchronously.
|
||||
|
||||
|
|
@ -12515,6 +12670,10 @@ public:
|
|||
|
||||
If called after triggerAsyncUpdate() and before the handleAsyncUpdate()
|
||||
callback happens, this will cancel the handleAsyncUpdate() callback.
|
||||
|
||||
Note that this method simply cancels the next callback - if a callback is already
|
||||
in progress on a different thread, this won't block until it finishes, so there's
|
||||
no guarantee that the callback isn't still running when you return from
|
||||
*/
|
||||
void cancelPendingUpdate() throw();
|
||||
|
||||
|
|
@ -12542,11 +12701,10 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
class AsyncUpdaterMessage;
|
||||
friend class AsyncUpdaterMessage;
|
||||
friend class ScopedPointer<AsyncUpdaterMessage>;
|
||||
ScopedPointer<AsyncUpdaterMessage> message;
|
||||
Atomic<AsyncUpdaterMessage*> pendingMessage;
|
||||
ReferenceCountedObjectPtr<CallbackMessage> message;
|
||||
Atomic<int>& getDeliveryFlag() const throw();
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncUpdater);
|
||||
};
|
||||
|
||||
#endif // __JUCE_ASYNCUPDATER_JUCEHEADER__
|
||||
|
|
@ -28476,64 +28634,6 @@ struct JUCE_API ApplicationCommandInfo
|
|||
#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. */
|
||||
|
||||
private:
|
||||
friend class MessageListener;
|
||||
friend class MessageManager;
|
||||
MessageListener* messageRecipient;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message);
|
||||
};
|
||||
|
||||
#endif // __JUCE_MESSAGE_JUCEHEADER__
|
||||
/*** End of inlined file: juce_Message.h ***/
|
||||
|
||||
/**
|
||||
MessageListener subclasses can post and receive Message objects.
|
||||
|
||||
|
|
@ -30889,6 +30989,8 @@ public:
|
|||
A set of routines to convert buffers of 32-bit floating point data to and from
|
||||
various integer formats.
|
||||
|
||||
Note that these functions are deprecated - the AudioData class provides a much more
|
||||
flexible set of conversion classes now.
|
||||
*/
|
||||
class JUCE_API AudioDataConverters
|
||||
{
|
||||
|
|
@ -32681,7 +32783,7 @@ public:
|
|||
If you're going to generate a thumbnail yourself, call this before using addBlock()
|
||||
to add the data.
|
||||
*/
|
||||
void reset (int numChannels, double sampleRate);
|
||||
void reset (int numChannels, double sampleRate, int64 totalSamplesInSource = 0);
|
||||
|
||||
/** Adds a block of level data to the thumbnail.
|
||||
Call reset() before using this, to tell the thumbnail about the data format.
|
||||
|
|
@ -43777,76 +43879,6 @@ private:
|
|||
#endif
|
||||
#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__
|
||||
|
||||
/*** Start of inlined file: juce_CallbackMessage.h ***/
|
||||
#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__
|
||||
#define __JUCE_CALLBACKMESSAGE_JUCEHEADER__
|
||||
|
||||
/**
|
||||
A message that calls a custom function 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.
|
||||
|
||||
Always create an instance of a CallbackMessage on the heap, as it will be
|
||||
deleted automatically after the message has been delivered.
|
||||
|
||||
@see MessageListener, MessageManager, ActionListener, ChangeListener
|
||||
*/
|
||||
class JUCE_API CallbackMessage : public Message
|
||||
{
|
||||
public:
|
||||
|
||||
CallbackMessage() throw();
|
||||
|
||||
/** Destructor. */
|
||||
~CallbackMessage();
|
||||
|
||||
/** Called when the message is delivered.
|
||||
|
||||
You should implement this method and make it do whatever action you want
|
||||
to perform.
|
||||
|
||||
Note that like all other messages, this object will be deleted immediately
|
||||
after this method has been invoked.
|
||||
*/
|
||||
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();
|
||||
|
||||
/** This can be used to indicate whether the MessageManager should delete the
|
||||
message after it has been delivered.
|
||||
By default, messages will be deleted, but you might want to disable this so that you
|
||||
can re-use the same message.
|
||||
*/
|
||||
void setMessageIsDeletedOnDelivery (bool shouldBeDeleted) throw() { deleteOnDelivery = shouldBeDeleted; }
|
||||
|
||||
/** Returns true if the message should be deleted after is has been delivered.
|
||||
@see setMessageIsDeletedOnDelivery
|
||||
*/
|
||||
bool isMessageDeletedOnDelivery() const throw() { return deleteOnDelivery; }
|
||||
|
||||
private:
|
||||
|
||||
bool deleteOnDelivery;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackMessage);
|
||||
};
|
||||
|
||||
#endif // __JUCE_CALLBACKMESSAGE_JUCEHEADER__
|
||||
/*** End of inlined file: juce_CallbackMessage.h ***/
|
||||
|
||||
|
||||
#endif
|
||||
#ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__
|
||||
|
||||
|
|
@ -44374,11 +44406,9 @@ public:
|
|||
bool lockWasGained() const throw() { return locked; }
|
||||
|
||||
private:
|
||||
class SharedEvents;
|
||||
class BlockingMessage;
|
||||
friend class SharedEvents;
|
||||
friend class BlockingMessage;
|
||||
SharedEvents* sharedEvents;
|
||||
friend class ReferenceCountedObjectPtr<BlockingMessage>;
|
||||
ReferenceCountedObjectPtr<BlockingMessage> blockingMessage;
|
||||
bool locked;
|
||||
|
||||
void init (Thread* thread, ThreadPoolJob* job);
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ public:
|
|||
void setThumbnail (AudioThumbnail* thumb)
|
||||
{
|
||||
if (thumb != 0)
|
||||
thumb->reset (buffer.getNumChannels(), writer->getSampleRate());
|
||||
thumb->reset (buffer.getNumChannels(), writer->getSampleRate(), 0);
|
||||
|
||||
const ScopedLock sl (thumbnailLock);
|
||||
thumbnailToUpdate = thumb;
|
||||
|
|
|
|||
|
|
@ -553,14 +553,15 @@ void AudioThumbnail::clear()
|
|||
sendChangeMessage();
|
||||
}
|
||||
|
||||
void AudioThumbnail::reset (int newNumChannels, double newSampleRate)
|
||||
void AudioThumbnail::reset (int newNumChannels, double newSampleRate, int64 totalSamplesInSource)
|
||||
{
|
||||
clear();
|
||||
|
||||
numChannels = newNumChannels;
|
||||
sampleRate = newSampleRate;
|
||||
totalSamples = totalSamplesInSource;
|
||||
|
||||
createChannels (0);
|
||||
createChannels (1 + (int) (totalSamplesInSource / samplesPerThumbSample));
|
||||
}
|
||||
|
||||
void AudioThumbnail::createChannels (const int length)
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ public:
|
|||
If you're going to generate a thumbnail yourself, call this before using addBlock()
|
||||
to add the data.
|
||||
*/
|
||||
void reset (int numChannels, double sampleRate);
|
||||
void reset (int numChannels, double sampleRate, int64 totalSamplesInSource = 0);
|
||||
|
||||
/** Adds a block of level data to the thumbnail.
|
||||
Call reset() before using this, to tell the thumbnail about the data format.
|
||||
|
|
|
|||
|
|
@ -581,6 +581,8 @@ public:
|
|||
A set of routines to convert buffers of 32-bit floating point data to and from
|
||||
various integer formats.
|
||||
|
||||
Note that these functions are deprecated - the AudioData class provides a much more
|
||||
flexible set of conversion classes now.
|
||||
*/
|
||||
class JUCE_API AudioDataConverters
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSec
|
|||
class ReferenceCountedArray
|
||||
{
|
||||
public:
|
||||
typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an empty array.
|
||||
@see ReferenceCountedObject, Array, OwnedArray
|
||||
|
|
@ -126,7 +128,7 @@ public:
|
|||
|
||||
@see getUnchecked
|
||||
*/
|
||||
inline const ReferenceCountedObjectPtr<ObjectClass> operator[] (const int index) const throw()
|
||||
inline const ObjectClassPtr operator[] (const int index) const throw()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
|
||||
|
|
@ -138,7 +140,7 @@ public:
|
|||
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||
it can be used when you're sure the index if always going to be legal.
|
||||
*/
|
||||
inline const ReferenceCountedObjectPtr<ObjectClass> getUnchecked (const int index) const throw()
|
||||
inline const ObjectClassPtr getUnchecked (const int index) const throw()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
jassert (isPositiveAndBelow (index, numUsed));
|
||||
|
|
@ -150,7 +152,7 @@ public:
|
|||
This will return a null pointer if the array's empty.
|
||||
@see getLast
|
||||
*/
|
||||
inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw()
|
||||
inline const ObjectClassPtr getFirst() const throw()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return numUsed > 0 ? data.elements [0]
|
||||
|
|
@ -162,7 +164,7 @@ public:
|
|||
This will return a null pointer if the array's empty.
|
||||
@see getFirst
|
||||
*/
|
||||
inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw()
|
||||
inline const ObjectClassPtr getLast() const throw()
|
||||
{
|
||||
const ScopedLockType lock (getLock());
|
||||
return numUsed > 0 ? data.elements [numUsed - 1]
|
||||
|
|
@ -436,6 +438,43 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/** Removes and returns an object from the array.
|
||||
|
||||
This will remove the object at a given index and return it, moving back all
|
||||
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||
nothing will happen and a null pointer will be returned.
|
||||
|
||||
@param indexToRemove the index of the element to remove
|
||||
@see remove, removeObject, removeRange
|
||||
*/
|
||||
const ObjectClassPtr removeAndReturn (const int indexToRemove)
|
||||
{
|
||||
ObjectClassPtr removedItem;
|
||||
const ScopedLockType lock (getLock());
|
||||
|
||||
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||
{
|
||||
ObjectClass** const e = data.elements + indexToRemove;
|
||||
|
||||
if (*e != 0)
|
||||
{
|
||||
removedItem = *e;
|
||||
(*e)->decReferenceCount();
|
||||
}
|
||||
|
||||
--numUsed;
|
||||
const int numberToShift = numUsed - indexToRemove;
|
||||
|
||||
if (numberToShift > 0)
|
||||
memmove (e, e + 1, numberToShift * sizeof (ObjectClass*));
|
||||
|
||||
if ((numUsed << 1) < data.numAllocated)
|
||||
minimiseStorageOverheads();
|
||||
}
|
||||
|
||||
return removedItem;
|
||||
}
|
||||
|
||||
/** Removes the first occurrence of a specified object from the array.
|
||||
|
||||
If the item isn't found, no action is taken. If it is found, it is
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 52
|
||||
#define JUCE_BUILDNUMBER 106
|
||||
#define JUCE_BUILDNUMBER 107
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
|
|||
|
|
@ -33,29 +33,35 @@ BEGIN_JUCE_NAMESPACE
|
|||
|
||||
|
||||
//==============================================================================
|
||||
class AsyncUpdater::AsyncUpdaterMessage : public CallbackMessage
|
||||
class AsyncUpdaterMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
AsyncUpdaterMessage (AsyncUpdater& owner_)
|
||||
: owner (owner_)
|
||||
{
|
||||
setMessageIsDeletedOnDelivery (false);
|
||||
}
|
||||
|
||||
void messageCallback()
|
||||
{
|
||||
if (owner.pendingMessage.compareAndSetBool (0, this))
|
||||
if (shouldDeliver.compareAndSetBool (0, 1))
|
||||
owner.handleAsyncUpdate();
|
||||
}
|
||||
|
||||
Atomic<int> shouldDeliver;
|
||||
|
||||
private:
|
||||
AsyncUpdater& owner;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
AsyncUpdater::AsyncUpdater()
|
||||
: message (new AsyncUpdaterMessage (*this))
|
||||
{
|
||||
message = new AsyncUpdaterMessage (*this);
|
||||
}
|
||||
|
||||
inline Atomic<int>& AsyncUpdater::getDeliveryFlag() const throw()
|
||||
{
|
||||
return static_cast <AsyncUpdaterMessage*> (message.getObject())->shouldDeliver;
|
||||
}
|
||||
|
||||
AsyncUpdater::~AsyncUpdater()
|
||||
|
|
@ -66,19 +72,18 @@ AsyncUpdater::~AsyncUpdater()
|
|||
// deleting this object, or find some other way to avoid such a race condition.
|
||||
jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager());
|
||||
|
||||
if (pendingMessage.exchange (0) != 0)
|
||||
message.release()->setMessageIsDeletedOnDelivery (true);
|
||||
getDeliveryFlag().set (0);
|
||||
}
|
||||
|
||||
void AsyncUpdater::triggerAsyncUpdate()
|
||||
{
|
||||
if (pendingMessage.compareAndSetBool (message, 0))
|
||||
if (getDeliveryFlag().compareAndSetBool (1, 0))
|
||||
message->post();
|
||||
}
|
||||
|
||||
void AsyncUpdater::cancelPendingUpdate() throw()
|
||||
{
|
||||
pendingMessage = 0;
|
||||
getDeliveryFlag().set (0);
|
||||
}
|
||||
|
||||
void AsyncUpdater::handleUpdateNowIfNeeded()
|
||||
|
|
@ -86,13 +91,13 @@ void AsyncUpdater::handleUpdateNowIfNeeded()
|
|||
// This can only be called by the event thread.
|
||||
jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
|
||||
|
||||
if (pendingMessage.exchange (0) != 0)
|
||||
if (getDeliveryFlag().exchange (0) != 0)
|
||||
handleAsyncUpdate();
|
||||
}
|
||||
|
||||
bool AsyncUpdater::isUpdatePending() const throw()
|
||||
{
|
||||
return pendingMessage.value != 0;
|
||||
return getDeliveryFlag().value != 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#define __JUCE_ASYNCUPDATER_JUCEHEADER__
|
||||
|
||||
#include "../core/juce_Atomic.h"
|
||||
#include "../containers/juce_ScopedPointer.h"
|
||||
#include "../events/juce_CallbackMessage.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -71,6 +71,10 @@ public:
|
|||
|
||||
If called after triggerAsyncUpdate() and before the handleAsyncUpdate()
|
||||
callback happens, this will cancel the handleAsyncUpdate() callback.
|
||||
|
||||
Note that this method simply cancels the next callback - if a callback is already
|
||||
in progress on a different thread, this won't block until it finishes, so there's
|
||||
no guarantee that the callback isn't still running when you return from
|
||||
*/
|
||||
void cancelPendingUpdate() throw();
|
||||
|
||||
|
|
@ -97,14 +101,12 @@ public:
|
|||
*/
|
||||
virtual void handleAsyncUpdate() = 0;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class AsyncUpdaterMessage;
|
||||
friend class AsyncUpdaterMessage;
|
||||
friend class ScopedPointer<AsyncUpdaterMessage>;
|
||||
ScopedPointer<AsyncUpdaterMessage> message;
|
||||
Atomic<AsyncUpdaterMessage*> pendingMessage;
|
||||
ReferenceCountedObjectPtr<CallbackMessage> message;
|
||||
Atomic<int>& getDeliveryFlag() const throw();
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncUpdater);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "juce_Message.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A message that calls a custom function when it gets delivered.
|
||||
|
|
@ -73,22 +74,8 @@ public:
|
|||
*/
|
||||
void post();
|
||||
|
||||
/** This can be used to indicate whether the MessageManager should delete the
|
||||
message after it has been delivered.
|
||||
By default, messages will be deleted, but you might want to disable this so that you
|
||||
can re-use the same message.
|
||||
*/
|
||||
void setMessageIsDeletedOnDelivery (bool shouldBeDeleted) throw() { deleteOnDelivery = shouldBeDeleted; }
|
||||
|
||||
/** Returns true if the message should be deleted after is has been delivered.
|
||||
@see setMessageIsDeletedOnDelivery
|
||||
*/
|
||||
bool isMessageDeletedOnDelivery() const throw() { return deleteOnDelivery; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
bool deleteOnDelivery;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackMessage);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@
|
|||
#ifndef __JUCE_MESSAGE_JUCEHEADER__
|
||||
#define __JUCE_MESSAGE_JUCEHEADER__
|
||||
|
||||
#include "../containers/juce_ReferenceCountedObject.h"
|
||||
class MessageListener;
|
||||
class MessageManager;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** The base class for objects that can be delivered to a MessageListener.
|
||||
|
||||
|
|
@ -38,7 +40,7 @@ class MessageManager;
|
|||
|
||||
@see MessageListener, MessageManager, ActionListener, ChangeListener
|
||||
*/
|
||||
class JUCE_API Message
|
||||
class JUCE_API Message : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
|
@ -70,6 +72,8 @@ public:
|
|||
int intParameter3; /**< user-defined integer value. */
|
||||
void* pointerParameter; /**< user-defined pointer value. */
|
||||
|
||||
/** A typedef for pointers to messages. */
|
||||
typedef ReferenceCountedObjectPtr <Message> Ptr;
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -84,11 +84,11 @@ MessageManager* MessageManager::getInstance() throw()
|
|||
void MessageManager::postMessageToQueue (Message* const message)
|
||||
{
|
||||
if (quitMessagePosted || ! juce_postMessageToSystemQueue (message))
|
||||
delete message;
|
||||
Message::Ptr deleter (message); // (this will delete messages that were just created with a 0 ref count)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
CallbackMessage::CallbackMessage() throw() : deleteOnDelivery (true) {}
|
||||
CallbackMessage::CallbackMessage() throw() {}
|
||||
CallbackMessage::~CallbackMessage() {}
|
||||
|
||||
void CallbackMessage::post()
|
||||
|
|
@ -103,7 +103,6 @@ void MessageManager::deliverMessage (Message* const message)
|
|||
{
|
||||
JUCE_TRY
|
||||
{
|
||||
ScopedPointer <Message> messageDeleter (message);
|
||||
MessageListener* const recipient = message->messageRecipient;
|
||||
|
||||
if (recipient == 0)
|
||||
|
|
@ -113,9 +112,6 @@ void MessageManager::deliverMessage (Message* const message)
|
|||
if (callbackMessage != 0)
|
||||
{
|
||||
callbackMessage->messageCallback();
|
||||
|
||||
if (! callbackMessage->isMessageDeletedOnDelivery())
|
||||
messageDeleter.release();
|
||||
}
|
||||
else if (message->intParameter1 == quitMessageId)
|
||||
{
|
||||
|
|
@ -201,9 +197,11 @@ bool MessageManager::isThisTheMessageThread() const throw()
|
|||
|
||||
void MessageManager::setCurrentThreadAsMessageThread()
|
||||
{
|
||||
if (messageThreadId != Thread::getCurrentThreadId())
|
||||
const Thread::ThreadID thisThread = Thread::getCurrentThreadId();
|
||||
|
||||
if (messageThreadId != thisThread)
|
||||
{
|
||||
messageThreadId = Thread::getCurrentThreadId();
|
||||
messageThreadId = thisThread;
|
||||
|
||||
// This is needed on windows to make sure the message window is created by this thread
|
||||
doPlatformSpecificShutdown();
|
||||
|
|
@ -228,48 +226,32 @@ bool MessageManager::currentThreadHasLockedMessageManager() const throw()
|
|||
accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
|
||||
in Cocoa).
|
||||
*/
|
||||
class MessageManagerLock::SharedEvents : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
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,
|
||||
this shared data must be kept in a separate, ref-counted container. */
|
||||
WaitableEvent lockedEvent, releaseEvent;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE (SharedEvents);
|
||||
};
|
||||
|
||||
class MessageManagerLock::BlockingMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {}
|
||||
BlockingMessage() {}
|
||||
|
||||
void messageCallback()
|
||||
{
|
||||
events->lockedEvent.signal();
|
||||
events->releaseEvent.wait();
|
||||
lockedEvent.signal();
|
||||
releaseEvent.wait();
|
||||
}
|
||||
|
||||
private:
|
||||
ReferenceCountedObjectPtr <MessageManagerLock::SharedEvents> events;
|
||||
WaitableEvent lockedEvent, releaseEvent;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlockingMessage);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
MessageManagerLock::MessageManagerLock (Thread* const threadToCheck)
|
||||
: sharedEvents (0),
|
||||
locked (false)
|
||||
: locked (false)
|
||||
{
|
||||
init (threadToCheck, 0);
|
||||
}
|
||||
|
||||
MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal)
|
||||
: sharedEvents (0),
|
||||
locked (false)
|
||||
: locked (false)
|
||||
{
|
||||
init (0, jobToCheckForExitSignal);
|
||||
}
|
||||
|
|
@ -300,19 +282,16 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const
|
|||
}
|
||||
}
|
||||
|
||||
sharedEvents = new SharedEvents();
|
||||
sharedEvents->incReferenceCount();
|
||||
blockingMessage = new BlockingMessage();
|
||||
blockingMessage->post();
|
||||
|
||||
(new BlockingMessage (sharedEvents))->post();
|
||||
|
||||
while (! sharedEvents->lockedEvent.wait (50))
|
||||
while (! blockingMessage->lockedEvent.wait (20))
|
||||
{
|
||||
if ((threadToCheck != 0 && threadToCheck->threadShouldExit())
|
||||
|| (job != 0 && job->shouldExit()))
|
||||
{
|
||||
sharedEvents->releaseEvent.signal();
|
||||
sharedEvents->decReferenceCount();
|
||||
sharedEvents = 0;
|
||||
blockingMessage->releaseEvent.signal();
|
||||
blockingMessage = 0;
|
||||
MessageManager::instance->lockingLock.exit();
|
||||
return;
|
||||
}
|
||||
|
|
@ -328,12 +307,12 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const
|
|||
|
||||
MessageManagerLock::~MessageManagerLock() throw()
|
||||
{
|
||||
if (sharedEvents != 0)
|
||||
if (blockingMessage != 0)
|
||||
{
|
||||
jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager());
|
||||
|
||||
sharedEvents->releaseEvent.signal();
|
||||
sharedEvents->decReferenceCount();
|
||||
blockingMessage->releaseEvent.signal();
|
||||
blockingMessage = 0;
|
||||
|
||||
if (MessageManager::instance != 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -299,11 +299,9 @@ public:
|
|||
|
||||
|
||||
private:
|
||||
class SharedEvents;
|
||||
class BlockingMessage;
|
||||
friend class SharedEvents;
|
||||
friend class BlockingMessage;
|
||||
SharedEvents* sharedEvents;
|
||||
friend class ReferenceCountedObjectPtr<BlockingMessage>;
|
||||
ReferenceCountedObjectPtr<BlockingMessage> blockingMessage;
|
||||
bool locked;
|
||||
|
||||
void init (Thread* thread, ThreadPoolJob* job);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ public:
|
|||
void run()
|
||||
{
|
||||
uint32 lastTime = Time::getMillisecondCounter();
|
||||
Message::Ptr message (new Message());
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
|
|
@ -89,7 +90,7 @@ public:
|
|||
*/
|
||||
if (callbackNeeded.compareAndSetBool (1, 0))
|
||||
{
|
||||
postMessage (new Message());
|
||||
postMessage (message);
|
||||
|
||||
/* Sometimes our message can get discarded by the OS (e.g. when running as an RTAS
|
||||
when the app has a modal loop), so this is how long to wait before assuming the
|
||||
|
|
|
|||
|
|
@ -1536,6 +1536,10 @@ void Component::exitModalState (const int returnValue)
|
|||
}
|
||||
else
|
||||
{
|
||||
// if component methods are being called from threads other than the message
|
||||
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
|
||||
CHECK_MESSAGE_MANAGER_IS_LOCKED
|
||||
|
||||
class ExitModalStateMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
|
|
@ -2111,6 +2115,10 @@ void Component::parentSizeChanged()
|
|||
|
||||
void Component::addComponentListener (ComponentListener* const newListener)
|
||||
{
|
||||
// if component methods are being called from threads other than the message
|
||||
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
|
||||
CHECK_MESSAGE_MANAGER_IS_LOCKED
|
||||
|
||||
componentListeners.add (newListener);
|
||||
}
|
||||
|
||||
|
|
@ -2156,6 +2164,10 @@ void Component::paintOverChildren (Graphics&)
|
|||
//==============================================================================
|
||||
void Component::postCommandMessage (const int commandId)
|
||||
{
|
||||
// if component methods are being called from threads other than the message
|
||||
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
|
||||
CHECK_MESSAGE_MANAGER_IS_LOCKED
|
||||
|
||||
class CustomCommandMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../application/juce_Application.h"
|
||||
#include "../utilities/juce_SystemClipboard.h"
|
||||
#include "../events/juce_MessageManager.h"
|
||||
#include "../containers/juce_ReferenceCountedArray.h"
|
||||
#include "../gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h"
|
||||
#include "../gui/graphics/imaging/juce_ImageFileFormat.h"
|
||||
#include "../gui/graphics/imaging/juce_CameraDevice.h"
|
||||
|
|
@ -112,6 +113,74 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class MessageQueue
|
||||
{
|
||||
public:
|
||||
MessageQueue()
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 && ! JUCE_IOS
|
||||
runLoop = CFRunLoopGetMain();
|
||||
#else
|
||||
runLoop = CFRunLoopGetCurrent();
|
||||
#endif
|
||||
|
||||
CFRunLoopSourceContext sourceContext;
|
||||
zerostruct (sourceContext);
|
||||
sourceContext.info = this;
|
||||
sourceContext.perform = runLoopSourceCallback;
|
||||
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
|
||||
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
}
|
||||
|
||||
~MessageQueue()
|
||||
{
|
||||
CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopSourceInvalidate (runLoopSource);
|
||||
CFRelease (runLoopSource);
|
||||
}
|
||||
|
||||
void post (Message* const message)
|
||||
{
|
||||
messages.add (message);
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
|
||||
private:
|
||||
ReferenceCountedArray <Message, CriticalSection> messages;
|
||||
CriticalSection lock;
|
||||
CFRunLoopRef runLoop;
|
||||
CFRunLoopSourceRef runLoopSource;
|
||||
|
||||
bool deliverNextMessage()
|
||||
{
|
||||
const Message::Ptr nextMessage (messages.removeAndReturn (0));
|
||||
|
||||
if (nextMessage == 0)
|
||||
return false;
|
||||
|
||||
const ScopedAutoReleasePool pool;
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
void runLoopCallback()
|
||||
{
|
||||
for (int i = 4; --i >= 0;)
|
||||
if (! deliverNextMessage())
|
||||
return;
|
||||
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
|
||||
static void runLoopSourceCallback (void* info)
|
||||
{
|
||||
static_cast <MessageQueue*> (info)->runLoopCallback();
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#define JUCE_INCLUDED_FILE 1
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ public:
|
|||
|
||||
private:
|
||||
CriticalSection lock;
|
||||
OwnedArray <Message> queue;
|
||||
ReferenceCountedArray <Message> queue;
|
||||
int fd[2];
|
||||
int bytesInSocket;
|
||||
int totalEventCount;
|
||||
|
|
@ -193,15 +193,15 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
Message* popNextMessage()
|
||||
const Message::Ptr popNextMessage()
|
||||
{
|
||||
ScopedLock sl (lock);
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
if (bytesInSocket > 0)
|
||||
{
|
||||
--bytesInSocket;
|
||||
|
||||
ScopedUnlock ul (lock);
|
||||
const ScopedUnlock ul (lock);
|
||||
unsigned char x;
|
||||
size_t numBytes = read (fd[1], &x, 1);
|
||||
(void) numBytes;
|
||||
|
|
@ -212,7 +212,7 @@ private:
|
|||
|
||||
bool dispatchNextInternalMessage()
|
||||
{
|
||||
ScopedPointer <Message> msg (popNextMessage());
|
||||
const Message::Ptr msg (popNextMessage());
|
||||
|
||||
if (msg == 0)
|
||||
return false;
|
||||
|
|
@ -228,7 +228,7 @@ private:
|
|||
else
|
||||
{
|
||||
// Handle "normal" messages
|
||||
MessageManager::getInstance()->deliverMessage (msg.release());
|
||||
MessageManager::getInstance()->deliverMessage (msg);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -107,79 +107,41 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
namespace iOSMessageLoopHelpers
|
||||
struct MessageDispatchSystem
|
||||
{
|
||||
static CFRunLoopRef runLoop = 0;
|
||||
static CFRunLoopSourceRef runLoopSource = 0;
|
||||
static OwnedArray <Message, CriticalSection>* pendingMessages = 0;
|
||||
static JuceCustomMessageHandler* juceCustomMessageHandler = 0;
|
||||
|
||||
void runLoopSourceCallback (void*)
|
||||
MessageDispatchSystem()
|
||||
: juceCustomMessageHandler (0)
|
||||
{
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
int numDispatched = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Message* const nextMessage = pendingMessages->removeAndReturn (0);
|
||||
|
||||
if (nextMessage == 0)
|
||||
return;
|
||||
|
||||
const ScopedAutoReleasePool pool;
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
|
||||
} while (++numDispatched <= 4);
|
||||
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
~MessageDispatchSystem()
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler];
|
||||
[juceCustomMessageHandler release];
|
||||
}
|
||||
|
||||
JuceCustomMessageHandler* juceCustomMessageHandler;
|
||||
MessageQueue messageQueue;
|
||||
};
|
||||
|
||||
static MessageDispatchSystem* dispatcher = 0;
|
||||
|
||||
void MessageManager::doPlatformSpecificInitialisation()
|
||||
{
|
||||
using namespace iOSMessageLoopHelpers;
|
||||
pendingMessages = new OwnedArray <Message, CriticalSection>();
|
||||
|
||||
runLoop = CFRunLoopGetCurrent();
|
||||
CFRunLoopSourceContext sourceContext;
|
||||
zerostruct (sourceContext);
|
||||
sourceContext.perform = runLoopSourceCallback;
|
||||
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
|
||||
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
|
||||
if (juceCustomMessageHandler == 0)
|
||||
juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init];
|
||||
if (dispatcher == 0)
|
||||
dispatcher = new MessageDispatchSystem();
|
||||
}
|
||||
|
||||
void MessageManager::doPlatformSpecificShutdown()
|
||||
{
|
||||
using namespace iOSMessageLoopHelpers;
|
||||
CFRunLoopSourceInvalidate (runLoopSource);
|
||||
CFRelease (runLoopSource);
|
||||
runLoopSource = 0;
|
||||
deleteAndZero (pendingMessages);
|
||||
|
||||
if (juceCustomMessageHandler != 0)
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler];
|
||||
[juceCustomMessageHandler release];
|
||||
juceCustomMessageHandler = 0;
|
||||
}
|
||||
deleteAndZero (dispatcher);
|
||||
}
|
||||
|
||||
bool juce_postMessageToSystemQueue (Message* message)
|
||||
{
|
||||
using namespace iOSMessageLoopHelpers;
|
||||
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
pendingMessages->add (message);
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
if (dispatcher != 0)
|
||||
dispatcher->messageQueue.post (message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -190,14 +152,14 @@ void MessageManager::broadcastMessage (const String& value)
|
|||
|
||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data)
|
||||
{
|
||||
using namespace iOSMessageLoopHelpers;
|
||||
|
||||
if (isThisTheMessageThread())
|
||||
{
|
||||
return (*callback) (data);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassert (dispatcher != 0); // trying to call this when the juce system isn't initialised..
|
||||
|
||||
// If a thread has a MessageManagerLock and then tries to call this method, it'll
|
||||
// deadlock because the message manager is blocked from running, so can never
|
||||
// call your function..
|
||||
|
|
@ -211,11 +173,11 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* call
|
|||
cmp.result = 0;
|
||||
cmp.hasBeenExecuted = false;
|
||||
|
||||
[juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:)
|
||||
withObject: [NSData dataWithBytesNoCopy: &cmp
|
||||
length: sizeof (cmp)
|
||||
freeWhenDone: NO]
|
||||
waitUntilDone: YES];
|
||||
[dispatcher->juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:)
|
||||
withObject: [NSData dataWithBytesNoCopy: &cmp
|
||||
length: sizeof (cmp)
|
||||
freeWhenDone: NO]
|
||||
waitUntilDone: YES];
|
||||
|
||||
return cmp.result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,12 +182,12 @@ const File File::getSpecialLocation (const SpecialLocationType type)
|
|||
case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break;
|
||||
|
||||
#if JUCE_IOS
|
||||
case userDocumentsDirectory: resultPath = getIOSSystemLocation (NSDocumentDirectory); break;
|
||||
case userDesktopDirectory: resultPath = getIOSSystemLocation (NSDesktopDirectory); break;
|
||||
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
|
||||
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
File tmp (getIOSSystemLocation (NSCachesDirectory));
|
||||
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
|
||||
tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension());
|
||||
tmp.createDirectory();
|
||||
return tmp.getFullPathName();
|
||||
|
|
|
|||
|
|
@ -44,24 +44,10 @@ class AppDelegateRedirector
|
|||
public:
|
||||
AppDelegateRedirector()
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
|
||||
runLoop = CFRunLoopGetMain();
|
||||
#else
|
||||
runLoop = CFRunLoopGetCurrent();
|
||||
#endif
|
||||
CFRunLoopSourceContext sourceContext;
|
||||
zerostruct (sourceContext);
|
||||
sourceContext.info = this;
|
||||
sourceContext.perform = runLoopSourceCallback;
|
||||
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
|
||||
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
}
|
||||
|
||||
virtual ~AppDelegateRedirector()
|
||||
{
|
||||
CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopSourceInvalidate (runLoopSource);
|
||||
CFRelease (runLoopSource);
|
||||
}
|
||||
|
||||
virtual NSApplicationTerminateReply shouldTerminate()
|
||||
|
|
@ -137,40 +123,13 @@ public:
|
|||
|
||||
void postMessage (Message* const m)
|
||||
{
|
||||
messages.add (m);
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
messageQueue.post (m);
|
||||
}
|
||||
|
||||
private:
|
||||
CFRunLoopRef runLoop;
|
||||
CFRunLoopSourceRef runLoopSource;
|
||||
OwnedArray <Message, CriticalSection> messages;
|
||||
|
||||
void runLoopCallback()
|
||||
{
|
||||
int numDispatched = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Message* const nextMessage = messages.removeAndReturn (0);
|
||||
|
||||
if (nextMessage == 0)
|
||||
return;
|
||||
|
||||
const ScopedAutoReleasePool pool;
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
|
||||
} while (++numDispatched <= 4);
|
||||
|
||||
CFRunLoopSourceSignal (runLoopSource);
|
||||
CFRunLoopWakeUp (runLoop);
|
||||
}
|
||||
|
||||
static void runLoopSourceCallback (void* info)
|
||||
{
|
||||
static_cast <AppDelegateRedirector*> (info)->runLoopCallback();
|
||||
}
|
||||
MessageQueue messageQueue;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,9 @@ static LRESULT CALLBACK juce_MessageWndProc (HWND h,
|
|||
// here in case there are windows modal dialog boxes doing their own
|
||||
// dispatch loop and not calling our version
|
||||
|
||||
MessageManager::getInstance()->deliverMessage ((Message*) lParam);
|
||||
Message* const message = reinterpret_cast <Message*> (lParam);
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
message->decReferenceCount();
|
||||
return 0;
|
||||
}
|
||||
else if (message == broadcastId)
|
||||
|
|
@ -153,7 +155,9 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
|
|||
{
|
||||
if (m.message == specialId && m.hwnd == juce_messageWindowHandle)
|
||||
{
|
||||
MessageManager::getInstance()->deliverMessage ((Message*) (void*) m.lParam);
|
||||
Message* const message = reinterpret_cast <Message*> (m.lParam);
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
message->decReferenceCount();
|
||||
}
|
||||
else if (m.message == WM_QUIT)
|
||||
{
|
||||
|
|
@ -184,6 +188,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
|
|||
//==============================================================================
|
||||
bool juce_postMessageToSystemQueue (Message* message)
|
||||
{
|
||||
message->incReferenceCount();
|
||||
return PostMessage (juce_messageWindowHandle, specialId, 0, (LPARAM) message) != 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue