1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-26 02:14:22 +00:00

Changed the Message class to be reference-counted, and used this to tighten up some messaging code. Minor tweaks to AudioThumbnail, ReferenceCountedArray.

This commit is contained in:
Julian Storer 2010-12-19 19:33:52 +00:00
parent 1a887cda63
commit d60f661789
22 changed files with 573 additions and 527 deletions

View file

@ -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;

View file

@ -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)

View file

@ -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.

View file

@ -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
{

View file

@ -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

View file

@ -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.

View file

@ -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;
}

View file

@ -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);
};

View file

@ -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);
};

View file

@ -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:

View file

@ -84,11 +84,11 @@ MessageManager* MessageManager::getInstance() throw()
void MessageManager::postMessageToQueue (Message* const message)
{
if (quitMessagePosted || ! juce_postMessageToSystemQueue (message))
delete message;
Message::Ptr deleter (message); // (this will delete messages that were just created with a 0 ref count)
}
//==============================================================================
CallbackMessage::CallbackMessage() throw() : deleteOnDelivery (true) {}
CallbackMessage::CallbackMessage() throw() {}
CallbackMessage::~CallbackMessage() {}
void CallbackMessage::post()
@ -103,7 +103,6 @@ void MessageManager::deliverMessage (Message* const message)
{
JUCE_TRY
{
ScopedPointer <Message> messageDeleter (message);
MessageListener* const recipient = message->messageRecipient;
if (recipient == 0)
@ -113,9 +112,6 @@ void MessageManager::deliverMessage (Message* const message)
if (callbackMessage != 0)
{
callbackMessage->messageCallback();
if (! callbackMessage->isMessageDeletedOnDelivery())
messageDeleter.release();
}
else if (message->intParameter1 == quitMessageId)
{
@ -201,9 +197,11 @@ bool MessageManager::isThisTheMessageThread() const throw()
void MessageManager::setCurrentThreadAsMessageThread()
{
if (messageThreadId != Thread::getCurrentThreadId())
const Thread::ThreadID thisThread = Thread::getCurrentThreadId();
if (messageThreadId != thisThread)
{
messageThreadId = Thread::getCurrentThreadId();
messageThreadId = thisThread;
// This is needed on windows to make sure the message window is created by this thread
doPlatformSpecificShutdown();
@ -228,48 +226,32 @@ bool MessageManager::currentThreadHasLockedMessageManager() const throw()
accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
in Cocoa).
*/
class MessageManagerLock::SharedEvents : public ReferenceCountedObject
{
public:
SharedEvents() {}
/* This class just holds a couple of events to communicate between the BlockingMessage
and the MessageManagerLock. Because both of these objects may be deleted at any time,
this shared data must be kept in a separate, ref-counted container. */
WaitableEvent lockedEvent, releaseEvent;
private:
JUCE_DECLARE_NON_COPYABLE (SharedEvents);
};
class MessageManagerLock::BlockingMessage : public CallbackMessage
{
public:
BlockingMessage (MessageManagerLock::SharedEvents* const events_) : events (events_) {}
BlockingMessage() {}
void messageCallback()
{
events->lockedEvent.signal();
events->releaseEvent.wait();
lockedEvent.signal();
releaseEvent.wait();
}
private:
ReferenceCountedObjectPtr <MessageManagerLock::SharedEvents> events;
WaitableEvent lockedEvent, releaseEvent;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlockingMessage);
};
//==============================================================================
MessageManagerLock::MessageManagerLock (Thread* const threadToCheck)
: sharedEvents (0),
locked (false)
: locked (false)
{
init (threadToCheck, 0);
}
MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal)
: sharedEvents (0),
locked (false)
: locked (false)
{
init (0, jobToCheckForExitSignal);
}
@ -300,19 +282,16 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const
}
}
sharedEvents = new SharedEvents();
sharedEvents->incReferenceCount();
blockingMessage = new BlockingMessage();
blockingMessage->post();
(new BlockingMessage (sharedEvents))->post();
while (! sharedEvents->lockedEvent.wait (50))
while (! blockingMessage->lockedEvent.wait (20))
{
if ((threadToCheck != 0 && threadToCheck->threadShouldExit())
|| (job != 0 && job->shouldExit()))
{
sharedEvents->releaseEvent.signal();
sharedEvents->decReferenceCount();
sharedEvents = 0;
blockingMessage->releaseEvent.signal();
blockingMessage = 0;
MessageManager::instance->lockingLock.exit();
return;
}
@ -328,12 +307,12 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const
MessageManagerLock::~MessageManagerLock() throw()
{
if (sharedEvents != 0)
if (blockingMessage != 0)
{
jassert (MessageManager::instance == 0 || MessageManager::instance->currentThreadHasLockedMessageManager());
sharedEvents->releaseEvent.signal();
sharedEvents->decReferenceCount();
blockingMessage->releaseEvent.signal();
blockingMessage = 0;
if (MessageManager::instance != 0)
{

View file

@ -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);

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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;

View file

@ -107,79 +107,41 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
}
//==============================================================================
namespace iOSMessageLoopHelpers
struct MessageDispatchSystem
{
static CFRunLoopRef runLoop = 0;
static CFRunLoopSourceRef runLoopSource = 0;
static OwnedArray <Message, CriticalSection>* pendingMessages = 0;
static JuceCustomMessageHandler* juceCustomMessageHandler = 0;
void runLoopSourceCallback (void*)
MessageDispatchSystem()
: juceCustomMessageHandler (0)
{
if (pendingMessages != 0)
{
int numDispatched = 0;
do
{
Message* const nextMessage = pendingMessages->removeAndReturn (0);
if (nextMessage == 0)
return;
const ScopedAutoReleasePool pool;
MessageManager::getInstance()->deliverMessage (nextMessage);
} while (++numDispatched <= 4);
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
}
juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init];
}
}
~MessageDispatchSystem()
{
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler];
[juceCustomMessageHandler release];
}
JuceCustomMessageHandler* juceCustomMessageHandler;
MessageQueue messageQueue;
};
static MessageDispatchSystem* dispatcher = 0;
void MessageManager::doPlatformSpecificInitialisation()
{
using namespace iOSMessageLoopHelpers;
pendingMessages = new OwnedArray <Message, CriticalSection>();
runLoop = CFRunLoopGetCurrent();
CFRunLoopSourceContext sourceContext;
zerostruct (sourceContext);
sourceContext.perform = runLoopSourceCallback;
runLoopSource = CFRunLoopSourceCreate (kCFAllocatorDefault, 1, &sourceContext);
CFRunLoopAddSource (runLoop, runLoopSource, kCFRunLoopCommonModes);
if (juceCustomMessageHandler == 0)
juceCustomMessageHandler = [[JuceCustomMessageHandler alloc] init];
if (dispatcher == 0)
dispatcher = new MessageDispatchSystem();
}
void MessageManager::doPlatformSpecificShutdown()
{
using namespace iOSMessageLoopHelpers;
CFRunLoopSourceInvalidate (runLoopSource);
CFRelease (runLoopSource);
runLoopSource = 0;
deleteAndZero (pendingMessages);
if (juceCustomMessageHandler != 0)
{
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceCustomMessageHandler];
[juceCustomMessageHandler release];
juceCustomMessageHandler = 0;
}
deleteAndZero (dispatcher);
}
bool juce_postMessageToSystemQueue (Message* message)
{
using namespace iOSMessageLoopHelpers;
if (pendingMessages != 0)
{
pendingMessages->add (message);
CFRunLoopSourceSignal (runLoopSource);
CFRunLoopWakeUp (runLoop);
}
if (dispatcher != 0)
dispatcher->messageQueue.post (message);
return true;
}
@ -190,14 +152,14 @@ void MessageManager::broadcastMessage (const String& value)
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data)
{
using namespace iOSMessageLoopHelpers;
if (isThisTheMessageThread())
{
return (*callback) (data);
}
else
{
jassert (dispatcher != 0); // trying to call this when the juce system isn't initialised..
// If a thread has a MessageManagerLock and then tries to call this method, it'll
// deadlock because the message manager is blocked from running, so can never
// call your function..
@ -211,11 +173,11 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* call
cmp.result = 0;
cmp.hasBeenExecuted = false;
[juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:)
withObject: [NSData dataWithBytesNoCopy: &cmp
length: sizeof (cmp)
freeWhenDone: NO]
waitUntilDone: YES];
[dispatcher->juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:)
withObject: [NSData dataWithBytesNoCopy: &cmp
length: sizeof (cmp)
freeWhenDone: NO]
waitUntilDone: YES];
return cmp.result;
}

View file

@ -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();

View file

@ -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;
};

View file

@ -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;
}