| @@ -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(); | |||
| (new BlockingMessage (sharedEvents))->post(); | |||
| blockingMessage = new BlockingMessage(); | |||
| blockingMessage->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; | |||
| 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() | |||
| { | |||
| 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(); | |||
| (new BlockingMessage (sharedEvents))->post(); | |||
| blockingMessage = new BlockingMessage(); | |||
| blockingMessage->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; | |||
| 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() | |||
| { | |||
| 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; | |||
| } | |||