| @@ -21666,7 +21666,7 @@ public: | |||||
| void setThumbnail (AudioThumbnail* thumb) | void setThumbnail (AudioThumbnail* thumb) | ||||
| { | { | ||||
| if (thumb != 0) | if (thumb != 0) | ||||
| thumb->reset (buffer.getNumChannels(), writer->getSampleRate()); | |||||
| thumb->reset (buffer.getNumChannels(), writer->getSampleRate(), 0); | |||||
| const ScopedLock sl (thumbnailLock); | const ScopedLock sl (thumbnailLock); | ||||
| thumbnailToUpdate = thumb; | thumbnailToUpdate = thumb; | ||||
| @@ -22475,14 +22475,15 @@ void AudioThumbnail::clear() | |||||
| sendChangeMessage(); | sendChangeMessage(); | ||||
| } | } | ||||
| void AudioThumbnail::reset (int newNumChannels, double newSampleRate) | |||||
| void AudioThumbnail::reset (int newNumChannels, double newSampleRate, int64 totalSamplesInSource) | |||||
| { | { | ||||
| clear(); | clear(); | ||||
| numChannels = newNumChannels; | numChannels = newNumChannels; | ||||
| sampleRate = newSampleRate; | sampleRate = newSampleRate; | ||||
| totalSamples = totalSamplesInSource; | |||||
| createChannels (0); | |||||
| createChannels (1 + (int) (totalSamplesInSource / samplesPerThumbSample)); | |||||
| } | } | ||||
| void AudioThumbnail::createChannels (const int length) | void AudioThumbnail::createChannels (const int length) | ||||
| @@ -38416,28 +38417,34 @@ END_JUCE_NAMESPACE | |||||
| /*** Start of inlined file: juce_AsyncUpdater.cpp ***/ | /*** Start of inlined file: juce_AsyncUpdater.cpp ***/ | ||||
| BEGIN_JUCE_NAMESPACE | BEGIN_JUCE_NAMESPACE | ||||
| class AsyncUpdater::AsyncUpdaterMessage : public CallbackMessage | |||||
| class AsyncUpdaterMessage : public CallbackMessage | |||||
| { | { | ||||
| public: | public: | ||||
| AsyncUpdaterMessage (AsyncUpdater& owner_) | AsyncUpdaterMessage (AsyncUpdater& owner_) | ||||
| : owner (owner_) | : owner (owner_) | ||||
| { | { | ||||
| setMessageIsDeletedOnDelivery (false); | |||||
| } | } | ||||
| void messageCallback() | void messageCallback() | ||||
| { | { | ||||
| if (owner.pendingMessage.compareAndSetBool (0, this)) | |||||
| if (shouldDeliver.compareAndSetBool (0, 1)) | |||||
| owner.handleAsyncUpdate(); | owner.handleAsyncUpdate(); | ||||
| } | } | ||||
| Atomic<int> shouldDeliver; | |||||
| private: | private: | ||||
| AsyncUpdater& owner; | AsyncUpdater& owner; | ||||
| }; | }; | ||||
| AsyncUpdater::AsyncUpdater() | 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() | AsyncUpdater::~AsyncUpdater() | ||||
| @@ -38448,19 +38455,18 @@ AsyncUpdater::~AsyncUpdater() | |||||
| // deleting this object, or find some other way to avoid such a race condition. | // deleting this object, or find some other way to avoid such a race condition. | ||||
| jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | ||||
| if (pendingMessage.exchange (0) != 0) | |||||
| message.release()->setMessageIsDeletedOnDelivery (true); | |||||
| getDeliveryFlag().set (0); | |||||
| } | } | ||||
| void AsyncUpdater::triggerAsyncUpdate() | void AsyncUpdater::triggerAsyncUpdate() | ||||
| { | { | ||||
| if (pendingMessage.compareAndSetBool (message, 0)) | |||||
| if (getDeliveryFlag().compareAndSetBool (1, 0)) | |||||
| message->post(); | message->post(); | ||||
| } | } | ||||
| void AsyncUpdater::cancelPendingUpdate() throw() | void AsyncUpdater::cancelPendingUpdate() throw() | ||||
| { | { | ||||
| pendingMessage = 0; | |||||
| getDeliveryFlag().set (0); | |||||
| } | } | ||||
| void AsyncUpdater::handleUpdateNowIfNeeded() | void AsyncUpdater::handleUpdateNowIfNeeded() | ||||
| @@ -38468,13 +38474,13 @@ void AsyncUpdater::handleUpdateNowIfNeeded() | |||||
| // This can only be called by the event thread. | // This can only be called by the event thread. | ||||
| jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | ||||
| if (pendingMessage.exchange (0) != 0) | |||||
| if (getDeliveryFlag().exchange (0) != 0) | |||||
| handleAsyncUpdate(); | handleAsyncUpdate(); | ||||
| } | } | ||||
| bool AsyncUpdater::isUpdatePending() const throw() | bool AsyncUpdater::isUpdatePending() const throw() | ||||
| { | { | ||||
| return pendingMessage.value != 0; | |||||
| return getDeliveryFlag().value != 0; | |||||
| } | } | ||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| @@ -39088,10 +39094,10 @@ MessageManager* MessageManager::getInstance() throw() | |||||
| void MessageManager::postMessageToQueue (Message* const message) | void MessageManager::postMessageToQueue (Message* const message) | ||||
| { | { | ||||
| if (quitMessagePosted || ! juce_postMessageToSystemQueue (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() {} | CallbackMessage::~CallbackMessage() {} | ||||
| void CallbackMessage::post() | void CallbackMessage::post() | ||||
| @@ -39105,7 +39111,6 @@ void MessageManager::deliverMessage (Message* const message) | |||||
| { | { | ||||
| JUCE_TRY | JUCE_TRY | ||||
| { | { | ||||
| ScopedPointer <Message> messageDeleter (message); | |||||
| MessageListener* const recipient = message->messageRecipient; | MessageListener* const recipient = message->messageRecipient; | ||||
| if (recipient == 0) | if (recipient == 0) | ||||
| @@ -39115,9 +39120,6 @@ void MessageManager::deliverMessage (Message* const message) | |||||
| if (callbackMessage != 0) | if (callbackMessage != 0) | ||||
| { | { | ||||
| callbackMessage->messageCallback(); | callbackMessage->messageCallback(); | ||||
| if (! callbackMessage->isMessageDeletedOnDelivery()) | |||||
| messageDeleter.release(); | |||||
| } | } | ||||
| else if (message->intParameter1 == quitMessageId) | else if (message->intParameter1 == quitMessageId) | ||||
| { | { | ||||
| @@ -39200,9 +39202,11 @@ bool MessageManager::isThisTheMessageThread() const throw() | |||||
| void MessageManager::setCurrentThreadAsMessageThread() | 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 | // This is needed on windows to make sure the message window is created by this thread | ||||
| doPlatformSpecificShutdown(); | 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 | accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens | ||||
| in Cocoa). | 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 | class MessageManagerLock::BlockingMessage : public CallbackMessage | ||||
| { | { | ||||
| public: | public: | ||||
| BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {} | |||||
| BlockingMessage() {} | |||||
| void messageCallback() | 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); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlockingMessage); | ||||
| }; | }; | ||||
| MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) | MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) | ||||
| : sharedEvents (0), | |||||
| locked (false) | |||||
| : locked (false) | |||||
| { | { | ||||
| init (threadToCheck, 0); | init (threadToCheck, 0); | ||||
| } | } | ||||
| MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) | MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) | ||||
| : sharedEvents (0), | |||||
| locked (false) | |||||
| : locked (false) | |||||
| { | { | ||||
| init (0, jobToCheckForExitSignal); | init (0, jobToCheckForExitSignal); | ||||
| } | } | ||||
| @@ -39296,19 +39284,16 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||||
| } | } | ||||
| } | } | ||||
| sharedEvents = new SharedEvents(); | |||||
| sharedEvents->incReferenceCount(); | |||||
| (new BlockingMessage (sharedEvents))->post(); | |||||
| blockingMessage = new BlockingMessage(); | |||||
| blockingMessage->post(); | |||||
| while (! sharedEvents->lockedEvent.wait (50)) | |||||
| while (! blockingMessage->lockedEvent.wait (20)) | |||||
| { | { | ||||
| if ((threadToCheck != 0 && threadToCheck->threadShouldExit()) | if ((threadToCheck != 0 && threadToCheck->threadShouldExit()) | ||||
| || (job != 0 && job->shouldExit())) | || (job != 0 && job->shouldExit())) | ||||
| { | { | ||||
| sharedEvents->releaseEvent.signal(); | |||||
| sharedEvents->decReferenceCount(); | |||||
| sharedEvents = 0; | |||||
| blockingMessage->releaseEvent.signal(); | |||||
| blockingMessage = 0; | |||||
| MessageManager::instance->lockingLock.exit(); | MessageManager::instance->lockingLock.exit(); | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -39324,12 +39309,12 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||||
| MessageManagerLock::~MessageManagerLock() throw() | MessageManagerLock::~MessageManagerLock() throw() | ||||
| { | { | ||||
| if (sharedEvents != 0) | |||||
| if (blockingMessage != 0) | |||||
| { | { | ||||
| jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager()); | jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager()); | ||||
| sharedEvents->releaseEvent.signal(); | |||||
| sharedEvents->decReferenceCount(); | |||||
| blockingMessage->releaseEvent.signal(); | |||||
| blockingMessage = 0; | |||||
| if (MessageManager::instance != 0) | if (MessageManager::instance != 0) | ||||
| { | { | ||||
| @@ -39478,6 +39463,7 @@ public: | |||||
| void run() | void run() | ||||
| { | { | ||||
| uint32 lastTime = Time::getMillisecondCounter(); | uint32 lastTime = Time::getMillisecondCounter(); | ||||
| Message::Ptr message (new Message()); | |||||
| while (! threadShouldExit()) | while (! threadShouldExit()) | ||||
| { | { | ||||
| @@ -39503,7 +39489,7 @@ public: | |||||
| */ | */ | ||||
| if (callbackNeeded.compareAndSetBool (1, 0)) | 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 | /* 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 | 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 | 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 | class ExitModalStateMessage : public CallbackMessage | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -41854,6 +41844,10 @@ void Component::parentSizeChanged() | |||||
| void Component::addComponentListener (ComponentListener* const newListener) | 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); | componentListeners.add (newListener); | ||||
| } | } | ||||
| @@ -41895,6 +41889,10 @@ void Component::paintOverChildren (Graphics&) | |||||
| void Component::postCommandMessage (const int commandId) | 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 | class CustomCommandMessage : public CallbackMessage | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -239896,7 +239894,9 @@ static LRESULT CALLBACK juce_MessageWndProc (HWND h, | |||||
| // here in case there are windows modal dialog boxes doing their own | // here in case there are windows modal dialog boxes doing their own | ||||
| // dispatch loop and not calling our version | // 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; | return 0; | ||||
| } | } | ||||
| else if (message == broadcastId) | else if (message == broadcastId) | ||||
| @@ -239984,7 +239984,9 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages | |||||
| { | { | ||||
| if (m.message == specialId && m.hwnd == juce_messageWindowHandle) | 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) | else if (m.message == WM_QUIT) | ||||
| { | { | ||||
| @@ -240014,6 +240016,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages | |||||
| bool juce_postMessageToSystemQueue (Message* message) | bool juce_postMessageToSystemQueue (Message* message) | ||||
| { | { | ||||
| message->incReferenceCount(); | |||||
| return PostMessage (juce_messageWindowHandle, specialId, 0, (LPARAM) message) != 0; | return PostMessage (juce_messageWindowHandle, specialId, 0, (LPARAM) message) != 0; | ||||
| } | } | ||||
| @@ -255883,7 +255886,7 @@ public: | |||||
| private: | private: | ||||
| CriticalSection lock; | CriticalSection lock; | ||||
| OwnedArray <Message> queue; | |||||
| ReferenceCountedArray <Message> queue; | |||||
| int fd[2]; | int fd[2]; | ||||
| int bytesInSocket; | int bytesInSocket; | ||||
| int totalEventCount; | int totalEventCount; | ||||
| @@ -255923,15 +255926,15 @@ private: | |||||
| return true; | return true; | ||||
| } | } | ||||
| Message* popNextMessage() | |||||
| const Message::Ptr popNextMessage() | |||||
| { | { | ||||
| ScopedLock sl (lock); | |||||
| const ScopedLock sl (lock); | |||||
| if (bytesInSocket > 0) | if (bytesInSocket > 0) | ||||
| { | { | ||||
| --bytesInSocket; | --bytesInSocket; | ||||
| ScopedUnlock ul (lock); | |||||
| const ScopedUnlock ul (lock); | |||||
| unsigned char x; | unsigned char x; | ||||
| size_t numBytes = read (fd[1], &x, 1); | size_t numBytes = read (fd[1], &x, 1); | ||||
| (void) numBytes; | (void) numBytes; | ||||
| @@ -255942,7 +255945,7 @@ private: | |||||
| bool dispatchNextInternalMessage() | bool dispatchNextInternalMessage() | ||||
| { | { | ||||
| ScopedPointer <Message> msg (popNextMessage()); | |||||
| const Message::Ptr msg (popNextMessage()); | |||||
| if (msg == 0) | if (msg == 0) | ||||
| return false; | return false; | ||||
| @@ -255958,7 +255961,7 @@ private: | |||||
| else | else | ||||
| { | { | ||||
| // Handle "normal" messages | // Handle "normal" messages | ||||
| MessageManager::getInstance()->deliverMessage (msg.release()); | |||||
| MessageManager::getInstance()->deliverMessage (msg); | |||||
| } | } | ||||
| return true; | 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 | #define JUCE_INCLUDED_FILE 1 | ||||
| // Now include the actual code files.. | // Now include the actual code files.. | ||||
| @@ -264281,12 +264351,12 @@ const File File::getSpecialLocation (const SpecialLocationType type) | |||||
| case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break; | case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break; | ||||
| #if JUCE_IOS | #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: | case tempDirectory: | ||||
| { | { | ||||
| File tmp (getIOSSystemLocation (NSCachesDirectory)); | |||||
| File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory)); | |||||
| tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension()); | tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension()); | ||||
| tmp.createDirectory(); | tmp.createDirectory(); | ||||
| return tmp.getFullPathName(); | return tmp.getFullPathName(); | ||||
| @@ -267433,79 +267503,41 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||||
| return ! quitMessagePosted; | 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; | |||||
| juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init]; | |||||
| } | |||||
| const ScopedAutoReleasePool pool; | |||||
| MessageManager::getInstance()->deliverMessage (nextMessage); | |||||
| ~MessageDispatchSystem() | |||||
| { | |||||
| [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler]; | |||||
| [juceCustomMessageHandler release]; | |||||
| } | |||||
| } while (++numDispatched <= 4); | |||||
| JuceCustomMessageHandler* juceCustomMessageHandler; | |||||
| MessageQueue messageQueue; | |||||
| }; | |||||
| CFRunLoopSourceSignal (runLoopSource); | |||||
| CFRunLoopWakeUp (runLoop); | |||||
| } | |||||
| } | |||||
| } | |||||
| static MessageDispatchSystem* dispatcher = 0; | |||||
| void MessageManager::doPlatformSpecificInitialisation() | 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() | 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) | 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; | return true; | ||||
| } | } | ||||
| @@ -267516,14 +267548,14 @@ void MessageManager::broadcastMessage (const String& value) | |||||
| void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | ||||
| { | { | ||||
| using namespace iOSMessageLoopHelpers; | |||||
| if (isThisTheMessageThread()) | if (isThisTheMessageThread()) | ||||
| { | { | ||||
| return (*callback) (data); | return (*callback) (data); | ||||
| } | } | ||||
| else | 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 | // 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 | // deadlock because the message manager is blocked from running, so can never | ||||
| // call your function.. | // call your function.. | ||||
| @@ -267537,11 +267569,11 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* call | |||||
| cmp.result = 0; | cmp.result = 0; | ||||
| cmp.hasBeenExecuted = false; | 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; | return cmp.result; | ||||
| } | } | ||||
| @@ -275660,24 +275692,10 @@ class AppDelegateRedirector | |||||
| public: | public: | ||||
| AppDelegateRedirector() | 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() | virtual ~AppDelegateRedirector() | ||||
| { | { | ||||
| CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes); | |||||
| CFRunLoopSourceInvalidate (runLoopSource); | |||||
| CFRelease (runLoopSource); | |||||
| } | } | ||||
| virtual NSApplicationTerminateReply shouldTerminate() | virtual NSApplicationTerminateReply shouldTerminate() | ||||
| @@ -275753,40 +275771,13 @@ public: | |||||
| void postMessage (Message* const m) | void postMessage (Message* const m) | ||||
| { | { | ||||
| messages.add (m); | |||||
| CFRunLoopSourceSignal (runLoopSource); | |||||
| CFRunLoopWakeUp (runLoop); | |||||
| messageQueue.post (m); | |||||
| } | } | ||||
| private: | private: | ||||
| CFRunLoopRef runLoop; | CFRunLoopRef runLoop; | ||||
| CFRunLoopSourceRef runLoopSource; | 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 | END_JUCE_NAMESPACE | ||||
| @@ -64,7 +64,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 52 | #define JUCE_MINOR_VERSION 52 | ||||
| #define JUCE_BUILDNUMBER 106 | |||||
| #define JUCE_BUILDNUMBER 107 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -11025,6 +11025,7 @@ template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSec | |||||
| class ReferenceCountedArray | class ReferenceCountedArray | ||||
| { | { | ||||
| public: | public: | ||||
| typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr; | |||||
| /** Creates an empty array. | /** Creates an empty array. | ||||
| @see ReferenceCountedObject, Array, OwnedArray | @see ReferenceCountedObject, Array, OwnedArray | ||||
| @@ -11101,7 +11102,7 @@ public: | |||||
| @see getUnchecked | @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()); | const ScopedLockType lock (getLock()); | ||||
| return isPositiveAndBelow (index, numUsed) ? data.elements [index] | 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 | 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. | 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()); | const ScopedLockType lock (getLock()); | ||||
| jassert (isPositiveAndBelow (index, numUsed)); | jassert (isPositiveAndBelow (index, numUsed)); | ||||
| @@ -11125,7 +11126,7 @@ public: | |||||
| This will return a null pointer if the array's empty. | This will return a null pointer if the array's empty. | ||||
| @see getLast | @see getLast | ||||
| */ | */ | ||||
| inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw() | |||||
| inline const ObjectClassPtr getFirst() const throw() | |||||
| { | { | ||||
| const ScopedLockType lock (getLock()); | const ScopedLockType lock (getLock()); | ||||
| return numUsed > 0 ? data.elements [0] | return numUsed > 0 ? data.elements [0] | ||||
| @@ -11137,7 +11138,7 @@ public: | |||||
| This will return a null pointer if the array's empty. | This will return a null pointer if the array's empty. | ||||
| @see getFirst | @see getFirst | ||||
| */ | */ | ||||
| inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw() | |||||
| inline const ObjectClassPtr getLast() const throw() | |||||
| { | { | ||||
| const ScopedLockType lock (getLock()); | const ScopedLockType lock (getLock()); | ||||
| return numUsed > 0 ? data.elements [numUsed - 1] | 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. | /** 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 | 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__ | #ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ | ||||
| #define __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. | Has a callback method that is triggered asynchronously. | ||||
| @@ -12515,6 +12670,10 @@ public: | |||||
| If called after triggerAsyncUpdate() and before the handleAsyncUpdate() | If called after triggerAsyncUpdate() and before the handleAsyncUpdate() | ||||
| callback happens, this will cancel the handleAsyncUpdate() callback. | 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(); | void cancelPendingUpdate() throw(); | ||||
| @@ -12542,11 +12701,10 @@ public: | |||||
| private: | 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__ | #endif // __JUCE_ASYNCUPDATER_JUCEHEADER__ | ||||
| @@ -28476,64 +28634,6 @@ struct JUCE_API ApplicationCommandInfo | |||||
| #ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ | #ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ | ||||
| #define __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. | 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 | A set of routines to convert buffers of 32-bit floating point data to and from | ||||
| various integer formats. | 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 | class JUCE_API AudioDataConverters | ||||
| { | { | ||||
| @@ -32681,7 +32783,7 @@ public: | |||||
| If you're going to generate a thumbnail yourself, call this before using addBlock() | If you're going to generate a thumbnail yourself, call this before using addBlock() | ||||
| to add the data. | 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. | /** Adds a block of level data to the thumbnail. | ||||
| Call reset() before using this, to tell the thumbnail about the data format. | Call reset() before using this, to tell the thumbnail about the data format. | ||||
| @@ -43777,76 +43879,6 @@ private: | |||||
| #endif | #endif | ||||
| #ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__ | #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 | #endif | ||||
| #ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ | #ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ | ||||
| @@ -44374,11 +44406,9 @@ public: | |||||
| bool lockWasGained() const throw() { return locked; } | bool lockWasGained() const throw() { return locked; } | ||||
| private: | private: | ||||
| class SharedEvents; | |||||
| class BlockingMessage; | class BlockingMessage; | ||||
| friend class SharedEvents; | |||||
| friend class BlockingMessage; | |||||
| SharedEvents* sharedEvents; | |||||
| friend class ReferenceCountedObjectPtr<BlockingMessage>; | |||||
| ReferenceCountedObjectPtr<BlockingMessage> blockingMessage; | |||||
| bool locked; | bool locked; | ||||
| void init (Thread* thread, ThreadPoolJob* job); | void init (Thread* thread, ThreadPoolJob* job); | ||||
| @@ -264,7 +264,7 @@ public: | |||||
| void setThumbnail (AudioThumbnail* thumb) | void setThumbnail (AudioThumbnail* thumb) | ||||
| { | { | ||||
| if (thumb != 0) | if (thumb != 0) | ||||
| thumb->reset (buffer.getNumChannels(), writer->getSampleRate()); | |||||
| thumb->reset (buffer.getNumChannels(), writer->getSampleRate(), 0); | |||||
| const ScopedLock sl (thumbnailLock); | const ScopedLock sl (thumbnailLock); | ||||
| thumbnailToUpdate = thumb; | thumbnailToUpdate = thumb; | ||||
| @@ -553,14 +553,15 @@ void AudioThumbnail::clear() | |||||
| sendChangeMessage(); | sendChangeMessage(); | ||||
| } | } | ||||
| void AudioThumbnail::reset (int newNumChannels, double newSampleRate) | |||||
| void AudioThumbnail::reset (int newNumChannels, double newSampleRate, int64 totalSamplesInSource) | |||||
| { | { | ||||
| clear(); | clear(); | ||||
| numChannels = newNumChannels; | numChannels = newNumChannels; | ||||
| sampleRate = newSampleRate; | sampleRate = newSampleRate; | ||||
| totalSamples = totalSamplesInSource; | |||||
| createChannels (0); | |||||
| createChannels (1 + (int) (totalSamplesInSource / samplesPerThumbSample)); | |||||
| } | } | ||||
| void AudioThumbnail::createChannels (const int length) | 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() | If you're going to generate a thumbnail yourself, call this before using addBlock() | ||||
| to add the data. | 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. | /** Adds a block of level data to the thumbnail. | ||||
| Call reset() before using this, to tell the thumbnail about the data format. | 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 | A set of routines to convert buffers of 32-bit floating point data to and from | ||||
| various integer formats. | 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 | class JUCE_API AudioDataConverters | ||||
| { | { | ||||
| @@ -49,6 +49,8 @@ template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSec | |||||
| class ReferenceCountedArray | class ReferenceCountedArray | ||||
| { | { | ||||
| public: | public: | ||||
| typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Creates an empty array. | /** Creates an empty array. | ||||
| @see ReferenceCountedObject, Array, OwnedArray | @see ReferenceCountedObject, Array, OwnedArray | ||||
| @@ -126,7 +128,7 @@ public: | |||||
| @see getUnchecked | @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()); | const ScopedLockType lock (getLock()); | ||||
| return isPositiveAndBelow (index, numUsed) ? data.elements [index] | 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 | 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. | 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()); | const ScopedLockType lock (getLock()); | ||||
| jassert (isPositiveAndBelow (index, numUsed)); | jassert (isPositiveAndBelow (index, numUsed)); | ||||
| @@ -150,7 +152,7 @@ public: | |||||
| This will return a null pointer if the array's empty. | This will return a null pointer if the array's empty. | ||||
| @see getLast | @see getLast | ||||
| */ | */ | ||||
| inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw() | |||||
| inline const ObjectClassPtr getFirst() const throw() | |||||
| { | { | ||||
| const ScopedLockType lock (getLock()); | const ScopedLockType lock (getLock()); | ||||
| return numUsed > 0 ? data.elements [0] | return numUsed > 0 ? data.elements [0] | ||||
| @@ -162,7 +164,7 @@ public: | |||||
| This will return a null pointer if the array's empty. | This will return a null pointer if the array's empty. | ||||
| @see getFirst | @see getFirst | ||||
| */ | */ | ||||
| inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw() | |||||
| inline const ObjectClassPtr getLast() const throw() | |||||
| { | { | ||||
| const ScopedLockType lock (getLock()); | const ScopedLockType lock (getLock()); | ||||
| return numUsed > 0 ? data.elements [numUsed - 1] | 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. | /** 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 | 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_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 52 | #define JUCE_MINOR_VERSION 52 | ||||
| #define JUCE_BUILDNUMBER 106 | |||||
| #define JUCE_BUILDNUMBER 107 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -33,29 +33,35 @@ BEGIN_JUCE_NAMESPACE | |||||
| //============================================================================== | //============================================================================== | ||||
| class AsyncUpdater::AsyncUpdaterMessage : public CallbackMessage | |||||
| class AsyncUpdaterMessage : public CallbackMessage | |||||
| { | { | ||||
| public: | public: | ||||
| AsyncUpdaterMessage (AsyncUpdater& owner_) | AsyncUpdaterMessage (AsyncUpdater& owner_) | ||||
| : owner (owner_) | : owner (owner_) | ||||
| { | { | ||||
| setMessageIsDeletedOnDelivery (false); | |||||
| } | } | ||||
| void messageCallback() | void messageCallback() | ||||
| { | { | ||||
| if (owner.pendingMessage.compareAndSetBool (0, this)) | |||||
| if (shouldDeliver.compareAndSetBool (0, 1)) | |||||
| owner.handleAsyncUpdate(); | owner.handleAsyncUpdate(); | ||||
| } | } | ||||
| Atomic<int> shouldDeliver; | |||||
| private: | private: | ||||
| AsyncUpdater& owner; | AsyncUpdater& owner; | ||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| AsyncUpdater::AsyncUpdater() | 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() | AsyncUpdater::~AsyncUpdater() | ||||
| @@ -66,19 +72,18 @@ AsyncUpdater::~AsyncUpdater() | |||||
| // deleting this object, or find some other way to avoid such a race condition. | // deleting this object, or find some other way to avoid such a race condition. | ||||
| jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | ||||
| if (pendingMessage.exchange (0) != 0) | |||||
| message.release()->setMessageIsDeletedOnDelivery (true); | |||||
| getDeliveryFlag().set (0); | |||||
| } | } | ||||
| void AsyncUpdater::triggerAsyncUpdate() | void AsyncUpdater::triggerAsyncUpdate() | ||||
| { | { | ||||
| if (pendingMessage.compareAndSetBool (message, 0)) | |||||
| if (getDeliveryFlag().compareAndSetBool (1, 0)) | |||||
| message->post(); | message->post(); | ||||
| } | } | ||||
| void AsyncUpdater::cancelPendingUpdate() throw() | void AsyncUpdater::cancelPendingUpdate() throw() | ||||
| { | { | ||||
| pendingMessage = 0; | |||||
| getDeliveryFlag().set (0); | |||||
| } | } | ||||
| void AsyncUpdater::handleUpdateNowIfNeeded() | void AsyncUpdater::handleUpdateNowIfNeeded() | ||||
| @@ -86,13 +91,13 @@ void AsyncUpdater::handleUpdateNowIfNeeded() | |||||
| // This can only be called by the event thread. | // This can only be called by the event thread. | ||||
| jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | ||||
| if (pendingMessage.exchange (0) != 0) | |||||
| if (getDeliveryFlag().exchange (0) != 0) | |||||
| handleAsyncUpdate(); | handleAsyncUpdate(); | ||||
| } | } | ||||
| bool AsyncUpdater::isUpdatePending() const throw() | bool AsyncUpdater::isUpdatePending() const throw() | ||||
| { | { | ||||
| return pendingMessage.value != 0; | |||||
| return getDeliveryFlag().value != 0; | |||||
| } | } | ||||
| @@ -27,7 +27,7 @@ | |||||
| #define __JUCE_ASYNCUPDATER_JUCEHEADER__ | #define __JUCE_ASYNCUPDATER_JUCEHEADER__ | ||||
| #include "../core/juce_Atomic.h" | #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() | If called after triggerAsyncUpdate() and before the handleAsyncUpdate() | ||||
| callback happens, this will cancel the handleAsyncUpdate() callback. | 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(); | void cancelPendingUpdate() throw(); | ||||
| @@ -97,14 +101,12 @@ public: | |||||
| */ | */ | ||||
| virtual void handleAsyncUpdate() = 0; | virtual void handleAsyncUpdate() = 0; | ||||
| private: | 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" | #include "juce_Message.h" | ||||
| //============================================================================== | //============================================================================== | ||||
| /** | /** | ||||
| A message that calls a custom function when it gets delivered. | A message that calls a custom function when it gets delivered. | ||||
| @@ -73,22 +74,8 @@ public: | |||||
| */ | */ | ||||
| void post(); | 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: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| bool deleteOnDelivery; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackMessage); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackMessage); | ||||
| }; | }; | ||||
| @@ -26,9 +26,11 @@ | |||||
| #ifndef __JUCE_MESSAGE_JUCEHEADER__ | #ifndef __JUCE_MESSAGE_JUCEHEADER__ | ||||
| #define __JUCE_MESSAGE_JUCEHEADER__ | #define __JUCE_MESSAGE_JUCEHEADER__ | ||||
| #include "../containers/juce_ReferenceCountedObject.h" | |||||
| class MessageListener; | class MessageListener; | ||||
| class MessageManager; | class MessageManager; | ||||
| //============================================================================== | //============================================================================== | ||||
| /** The base class for objects that can be delivered to a MessageListener. | /** The base class for objects that can be delivered to a MessageListener. | ||||
| @@ -38,7 +40,7 @@ class MessageManager; | |||||
| @see MessageListener, MessageManager, ActionListener, ChangeListener | @see MessageListener, MessageManager, ActionListener, ChangeListener | ||||
| */ | */ | ||||
| class JUCE_API Message | |||||
| class JUCE_API Message : public ReferenceCountedObject | |||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -70,6 +72,8 @@ public: | |||||
| int intParameter3; /**< user-defined integer value. */ | int intParameter3; /**< user-defined integer value. */ | ||||
| void* pointerParameter; /**< user-defined pointer value. */ | void* pointerParameter; /**< user-defined pointer value. */ | ||||
| /** A typedef for pointers to messages. */ | |||||
| typedef ReferenceCountedObjectPtr <Message> Ptr; | |||||
| //============================================================================== | //============================================================================== | ||||
| private: | private: | ||||
| @@ -84,11 +84,11 @@ MessageManager* MessageManager::getInstance() throw() | |||||
| void MessageManager::postMessageToQueue (Message* const message) | void MessageManager::postMessageToQueue (Message* const message) | ||||
| { | { | ||||
| if (quitMessagePosted || ! juce_postMessageToSystemQueue (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() {} | CallbackMessage::~CallbackMessage() {} | ||||
| void CallbackMessage::post() | void CallbackMessage::post() | ||||
| @@ -103,7 +103,6 @@ void MessageManager::deliverMessage (Message* const message) | |||||
| { | { | ||||
| JUCE_TRY | JUCE_TRY | ||||
| { | { | ||||
| ScopedPointer <Message> messageDeleter (message); | |||||
| MessageListener* const recipient = message->messageRecipient; | MessageListener* const recipient = message->messageRecipient; | ||||
| if (recipient == 0) | if (recipient == 0) | ||||
| @@ -113,9 +112,6 @@ void MessageManager::deliverMessage (Message* const message) | |||||
| if (callbackMessage != 0) | if (callbackMessage != 0) | ||||
| { | { | ||||
| callbackMessage->messageCallback(); | callbackMessage->messageCallback(); | ||||
| if (! callbackMessage->isMessageDeletedOnDelivery()) | |||||
| messageDeleter.release(); | |||||
| } | } | ||||
| else if (message->intParameter1 == quitMessageId) | else if (message->intParameter1 == quitMessageId) | ||||
| { | { | ||||
| @@ -201,9 +197,11 @@ bool MessageManager::isThisTheMessageThread() const throw() | |||||
| void MessageManager::setCurrentThreadAsMessageThread() | 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 | // This is needed on windows to make sure the message window is created by this thread | ||||
| doPlatformSpecificShutdown(); | 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 | accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens | ||||
| in Cocoa). | 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 | class MessageManagerLock::BlockingMessage : public CallbackMessage | ||||
| { | { | ||||
| public: | public: | ||||
| BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {} | |||||
| BlockingMessage() {} | |||||
| void messageCallback() | 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); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlockingMessage); | ||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) | MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) | ||||
| : sharedEvents (0), | |||||
| locked (false) | |||||
| : locked (false) | |||||
| { | { | ||||
| init (threadToCheck, 0); | init (threadToCheck, 0); | ||||
| } | } | ||||
| MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) | MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) | ||||
| : sharedEvents (0), | |||||
| locked (false) | |||||
| : locked (false) | |||||
| { | { | ||||
| init (0, jobToCheckForExitSignal); | init (0, jobToCheckForExitSignal); | ||||
| } | } | ||||
| @@ -300,19 +282,16 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||||
| } | } | ||||
| } | } | ||||
| sharedEvents = new SharedEvents(); | |||||
| sharedEvents->incReferenceCount(); | |||||
| (new BlockingMessage (sharedEvents))->post(); | |||||
| blockingMessage = new BlockingMessage(); | |||||
| blockingMessage->post(); | |||||
| while (! sharedEvents->lockedEvent.wait (50)) | |||||
| while (! blockingMessage->lockedEvent.wait (20)) | |||||
| { | { | ||||
| if ((threadToCheck != 0 && threadToCheck->threadShouldExit()) | if ((threadToCheck != 0 && threadToCheck->threadShouldExit()) | ||||
| || (job != 0 && job->shouldExit())) | || (job != 0 && job->shouldExit())) | ||||
| { | { | ||||
| sharedEvents->releaseEvent.signal(); | |||||
| sharedEvents->decReferenceCount(); | |||||
| sharedEvents = 0; | |||||
| blockingMessage->releaseEvent.signal(); | |||||
| blockingMessage = 0; | |||||
| MessageManager::instance->lockingLock.exit(); | MessageManager::instance->lockingLock.exit(); | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -328,12 +307,12 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||||
| MessageManagerLock::~MessageManagerLock() throw() | MessageManagerLock::~MessageManagerLock() throw() | ||||
| { | { | ||||
| if (sharedEvents != 0) | |||||
| if (blockingMessage != 0) | |||||
| { | { | ||||
| jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager()); | jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager()); | ||||
| sharedEvents->releaseEvent.signal(); | |||||
| sharedEvents->decReferenceCount(); | |||||
| blockingMessage->releaseEvent.signal(); | |||||
| blockingMessage = 0; | |||||
| if (MessageManager::instance != 0) | if (MessageManager::instance != 0) | ||||
| { | { | ||||
| @@ -299,11 +299,9 @@ public: | |||||
| private: | private: | ||||
| class SharedEvents; | |||||
| class BlockingMessage; | class BlockingMessage; | ||||
| friend class SharedEvents; | |||||
| friend class BlockingMessage; | |||||
| SharedEvents* sharedEvents; | |||||
| friend class ReferenceCountedObjectPtr<BlockingMessage>; | |||||
| ReferenceCountedObjectPtr<BlockingMessage> blockingMessage; | |||||
| bool locked; | bool locked; | ||||
| void init (Thread* thread, ThreadPoolJob* job); | void init (Thread* thread, ThreadPoolJob* job); | ||||
| @@ -64,6 +64,7 @@ public: | |||||
| void run() | void run() | ||||
| { | { | ||||
| uint32 lastTime = Time::getMillisecondCounter(); | uint32 lastTime = Time::getMillisecondCounter(); | ||||
| Message::Ptr message (new Message()); | |||||
| while (! threadShouldExit()) | while (! threadShouldExit()) | ||||
| { | { | ||||
| @@ -89,7 +90,7 @@ public: | |||||
| */ | */ | ||||
| if (callbackNeeded.compareAndSetBool (1, 0)) | 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 | /* 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 | 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 | 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 | class ExitModalStateMessage : public CallbackMessage | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -2111,6 +2115,10 @@ void Component::parentSizeChanged() | |||||
| void Component::addComponentListener (ComponentListener* const newListener) | 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); | componentListeners.add (newListener); | ||||
| } | } | ||||
| @@ -2156,6 +2164,10 @@ void Component::paintOverChildren (Graphics&) | |||||
| //============================================================================== | //============================================================================== | ||||
| void Component::postCommandMessage (const int commandId) | 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 | class CustomCommandMessage : public CallbackMessage | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -63,6 +63,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| #include "../application/juce_Application.h" | #include "../application/juce_Application.h" | ||||
| #include "../utilities/juce_SystemClipboard.h" | #include "../utilities/juce_SystemClipboard.h" | ||||
| #include "../events/juce_MessageManager.h" | #include "../events/juce_MessageManager.h" | ||||
| #include "../containers/juce_ReferenceCountedArray.h" | |||||
| #include "../gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h" | #include "../gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h" | ||||
| #include "../gui/graphics/imaging/juce_ImageFileFormat.h" | #include "../gui/graphics/imaging/juce_ImageFileFormat.h" | ||||
| #include "../gui/graphics/imaging/juce_CameraDevice.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 | #define JUCE_INCLUDED_FILE 1 | ||||
| @@ -153,7 +153,7 @@ public: | |||||
| private: | private: | ||||
| CriticalSection lock; | CriticalSection lock; | ||||
| OwnedArray <Message> queue; | |||||
| ReferenceCountedArray <Message> queue; | |||||
| int fd[2]; | int fd[2]; | ||||
| int bytesInSocket; | int bytesInSocket; | ||||
| int totalEventCount; | int totalEventCount; | ||||
| @@ -193,15 +193,15 @@ private: | |||||
| return true; | return true; | ||||
| } | } | ||||
| Message* popNextMessage() | |||||
| const Message::Ptr popNextMessage() | |||||
| { | { | ||||
| ScopedLock sl (lock); | |||||
| const ScopedLock sl (lock); | |||||
| if (bytesInSocket > 0) | if (bytesInSocket > 0) | ||||
| { | { | ||||
| --bytesInSocket; | --bytesInSocket; | ||||
| ScopedUnlock ul (lock); | |||||
| const ScopedUnlock ul (lock); | |||||
| unsigned char x; | unsigned char x; | ||||
| size_t numBytes = read (fd[1], &x, 1); | size_t numBytes = read (fd[1], &x, 1); | ||||
| (void) numBytes; | (void) numBytes; | ||||
| @@ -212,7 +212,7 @@ private: | |||||
| bool dispatchNextInternalMessage() | bool dispatchNextInternalMessage() | ||||
| { | { | ||||
| ScopedPointer <Message> msg (popNextMessage()); | |||||
| const Message::Ptr msg (popNextMessage()); | |||||
| if (msg == 0) | if (msg == 0) | ||||
| return false; | return false; | ||||
| @@ -228,7 +228,7 @@ private: | |||||
| else | else | ||||
| { | { | ||||
| // Handle "normal" messages | // Handle "normal" messages | ||||
| MessageManager::getInstance()->deliverMessage (msg.release()); | |||||
| MessageManager::getInstance()->deliverMessage (msg); | |||||
| } | } | ||||
| return true; | 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; | |||||
| juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init]; | |||||
| } | |||||
| const ScopedAutoReleasePool pool; | |||||
| MessageManager::getInstance()->deliverMessage (nextMessage); | |||||
| ~MessageDispatchSystem() | |||||
| { | |||||
| [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler]; | |||||
| [juceCustomMessageHandler release]; | |||||
| } | |||||
| } while (++numDispatched <= 4); | |||||
| JuceCustomMessageHandler* juceCustomMessageHandler; | |||||
| MessageQueue messageQueue; | |||||
| }; | |||||
| CFRunLoopSourceSignal (runLoopSource); | |||||
| CFRunLoopWakeUp (runLoop); | |||||
| } | |||||
| } | |||||
| } | |||||
| static MessageDispatchSystem* dispatcher = 0; | |||||
| void MessageManager::doPlatformSpecificInitialisation() | 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() | 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) | 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; | return true; | ||||
| } | } | ||||
| @@ -190,14 +152,14 @@ void MessageManager::broadcastMessage (const String& value) | |||||
| void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | ||||
| { | { | ||||
| using namespace iOSMessageLoopHelpers; | |||||
| if (isThisTheMessageThread()) | if (isThisTheMessageThread()) | ||||
| { | { | ||||
| return (*callback) (data); | return (*callback) (data); | ||||
| } | } | ||||
| else | 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 | // 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 | // deadlock because the message manager is blocked from running, so can never | ||||
| // call your function.. | // call your function.. | ||||
| @@ -211,11 +173,11 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* call | |||||
| cmp.result = 0; | cmp.result = 0; | ||||
| cmp.hasBeenExecuted = false; | 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; | return cmp.result; | ||||
| } | } | ||||
| @@ -182,12 +182,12 @@ const File File::getSpecialLocation (const SpecialLocationType type) | |||||
| case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break; | case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break; | ||||
| #if JUCE_IOS | #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: | case tempDirectory: | ||||
| { | { | ||||
| File tmp (getIOSSystemLocation (NSCachesDirectory)); | |||||
| File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory)); | |||||
| tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension()); | tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension()); | ||||
| tmp.createDirectory(); | tmp.createDirectory(); | ||||
| return tmp.getFullPathName(); | return tmp.getFullPathName(); | ||||
| @@ -44,24 +44,10 @@ class AppDelegateRedirector | |||||
| public: | public: | ||||
| AppDelegateRedirector() | 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() | virtual ~AppDelegateRedirector() | ||||
| { | { | ||||
| CFRunLoopRemoveSource (runLoop, runLoopSource, kCFRunLoopCommonModes); | |||||
| CFRunLoopSourceInvalidate (runLoopSource); | |||||
| CFRelease (runLoopSource); | |||||
| } | } | ||||
| virtual NSApplicationTerminateReply shouldTerminate() | virtual NSApplicationTerminateReply shouldTerminate() | ||||
| @@ -137,40 +123,13 @@ public: | |||||
| void postMessage (Message* const m) | void postMessage (Message* const m) | ||||
| { | { | ||||
| messages.add (m); | |||||
| CFRunLoopSourceSignal (runLoopSource); | |||||
| CFRunLoopWakeUp (runLoop); | |||||
| messageQueue.post (m); | |||||
| } | } | ||||
| private: | private: | ||||
| CFRunLoopRef runLoop; | CFRunLoopRef runLoop; | ||||
| CFRunLoopSourceRef runLoopSource; | 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 | // here in case there are windows modal dialog boxes doing their own | ||||
| // dispatch loop and not calling our version | // 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; | return 0; | ||||
| } | } | ||||
| else if (message == broadcastId) | else if (message == broadcastId) | ||||
| @@ -153,7 +155,9 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages | |||||
| { | { | ||||
| if (m.message == specialId && m.hwnd == juce_messageWindowHandle) | 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) | else if (m.message == WM_QUIT) | ||||
| { | { | ||||
| @@ -184,6 +188,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages | |||||
| //============================================================================== | //============================================================================== | ||||
| bool juce_postMessageToSystemQueue (Message* message) | bool juce_postMessageToSystemQueue (Message* message) | ||||
| { | { | ||||
| message->incReferenceCount(); | |||||
| return PostMessage (juce_messageWindowHandle, specialId, 0, (LPARAM) message) != 0; | return PostMessage (juce_messageWindowHandle, specialId, 0, (LPARAM) message) != 0; | ||||
| } | } | ||||