@@ -41,6 +41,8 @@ public: | |||||
private: | private: | ||||
AsyncUpdater& owner; | AsyncUpdater& owner; | ||||
JUCE_DECLARE_NON_COPYABLE (AsyncUpdaterMessage); | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
@@ -192,15 +192,12 @@ private: | |||||
//============================================================================== | //============================================================================== | ||||
friend class InterprocessConnectionServer; | friend class InterprocessConnectionServer; | ||||
void initialiseWithSocket (StreamingSocket* socket_); | |||||
void initialiseWithPipe (NamedPipe* pipe_); | |||||
void handleMessage (const Message& message); | |||||
void initialiseWithSocket (StreamingSocket*); | |||||
void initialiseWithPipe (NamedPipe*); | |||||
void handleMessage (const Message&); | |||||
void connectionMadeInt(); | void connectionMadeInt(); | ||||
void connectionLostInt(); | void connectionLostInt(); | ||||
void deliverDataInt (const MemoryBlock& data); | |||||
void deliverDataInt (const MemoryBlock&); | |||||
bool readNextMessageInt(); | bool readNextMessageInt(); | ||||
void run(); | void run(); | ||||
@@ -32,16 +32,27 @@ CallbackMessage::~CallbackMessage() {} | |||||
void CallbackMessage::post() | void CallbackMessage::post() | ||||
{ | { | ||||
if (MessageManager::instance != nullptr) | |||||
MessageManager::instance->postMessageToQueue (this); | |||||
MessageManager* const mm = MessageManager::instance; | |||||
if (mm != nullptr) | |||||
mm->postMessageToQueue (this); | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
struct QuitMessage : public Message | |||||
class MessageManager::QuitMessage : public CallbackMessage | |||||
{ | { | ||||
QuitMessage() noexcept {} | |||||
}; | |||||
public: | |||||
QuitMessage() {} | |||||
void messageCallback() | |||||
{ | |||||
MessageManager* const mm = MessageManager::instance; | |||||
if (mm != nullptr) | |||||
mm->quitMessageReceived = true; | |||||
} | |||||
private: | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (QuitMessage); | |||||
}; | |||||
//============================================================================== | //============================================================================== | ||||
MessageManager* MessageManager::instance = nullptr; | MessageManager* MessageManager::instance = nullptr; | ||||
@@ -103,13 +114,7 @@ void MessageManager::deliverMessage (Message* const message) | |||||
CallbackMessage* const callbackMessage = dynamic_cast <CallbackMessage*> (message); | CallbackMessage* const callbackMessage = dynamic_cast <CallbackMessage*> (message); | ||||
if (callbackMessage != nullptr) | if (callbackMessage != nullptr) | ||||
{ | |||||
callbackMessage->messageCallback(); | callbackMessage->messageCallback(); | ||||
} | |||||
else if (dynamic_cast <QuitMessage*> (message) != nullptr) | |||||
{ | |||||
quitMessageReceived = true; | |||||
} | |||||
} | } | ||||
else if (messageListeners.contains (recipient)) | else if (messageListeners.contains (recipient)) | ||||
{ | { | ||||
@@ -130,8 +135,7 @@ void MessageManager::runDispatchLoop() | |||||
void MessageManager::stopDispatchLoop() | void MessageManager::stopDispatchLoop() | ||||
{ | { | ||||
postMessageToQueue (new QuitMessage()); | |||||
quitMessagePosted = true; | |||||
(new QuitMessage())->post(); | |||||
} | } | ||||
bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | ||||
@@ -161,6 +165,41 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||||
#endif | #endif | ||||
//============================================================================== | |||||
class AsyncFunctionCallback : public CallbackMessage | |||||
{ | |||||
public: | |||||
AsyncFunctionCallback (MessageCallbackFunction* const f, void* const param) | |||||
: result (nullptr), func (f), parameter (param) | |||||
{} | |||||
void messageCallback() | |||||
{ | |||||
result = (*func) (parameter); | |||||
finished.signal(); | |||||
} | |||||
WaitableEvent finished; | |||||
void* volatile result; | |||||
private: | |||||
MessageCallbackFunction* const func; | |||||
void* const parameter; | |||||
JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback); | |||||
}; | |||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* const func, void* const parameter) | |||||
{ | |||||
if (MessageManager::getInstance()->isThisTheMessageThread()) | |||||
return func (parameter); | |||||
const ReferenceCountedObjectPtr<AsyncFunctionCallback> message (new AsyncFunctionCallback (func, parameter)); | |||||
message->post(); | |||||
message->finished.wait(); | |||||
return message->result; | |||||
} | |||||
//============================================================================== | //============================================================================== | ||||
void MessageManager::deliverBroadcastMessage (const String& value) | void MessageManager::deliverBroadcastMessage (const String& value) | ||||
{ | { | ||||
@@ -249,25 +288,27 @@ MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSi | |||||
bool MessageManagerLock::attemptLock (Thread* const threadToCheck, ThreadPoolJob* const job) | bool MessageManagerLock::attemptLock (Thread* const threadToCheck, ThreadPoolJob* const job) | ||||
{ | { | ||||
if (MessageManager::instance == nullptr) | |||||
MessageManager* const mm = MessageManager::instance; | |||||
if (mm == nullptr) | |||||
return false; | return false; | ||||
if (MessageManager::instance->currentThreadHasLockedMessageManager()) | |||||
if (mm->currentThreadHasLockedMessageManager()) | |||||
return true; | return true; | ||||
if (threadToCheck == nullptr && job == nullptr) | if (threadToCheck == nullptr && job == nullptr) | ||||
{ | { | ||||
MessageManager::instance->lockingLock.enter(); | |||||
mm->lockingLock.enter(); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
while (! MessageManager::instance->lockingLock.tryEnter()) | |||||
while (! mm->lockingLock.tryEnter()) | |||||
{ | { | ||||
if ((threadToCheck != nullptr && threadToCheck->threadShouldExit()) | if ((threadToCheck != nullptr && threadToCheck->threadShouldExit()) | ||||
|| (job != nullptr && job->shouldExit())) | || (job != nullptr && job->shouldExit())) | ||||
return false; | return false; | ||||
Thread::sleep (1); | |||||
Thread::yield(); | |||||
} | } | ||||
} | } | ||||
@@ -281,14 +322,14 @@ bool MessageManagerLock::attemptLock (Thread* const threadToCheck, ThreadPoolJob | |||||
{ | { | ||||
blockingMessage->releaseEvent.signal(); | blockingMessage->releaseEvent.signal(); | ||||
blockingMessage = nullptr; | blockingMessage = nullptr; | ||||
MessageManager::instance->lockingLock.exit(); | |||||
mm->lockingLock.exit(); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
jassert (MessageManager::instance->threadWithLock == 0); | |||||
jassert (mm->threadWithLock == 0); | |||||
MessageManager::instance->threadWithLock = Thread::getCurrentThreadId(); | |||||
mm->threadWithLock = Thread::getCurrentThreadId(); | |||||
return true; | return true; | ||||
} | } | ||||
@@ -296,15 +337,17 @@ MessageManagerLock::~MessageManagerLock() noexcept | |||||
{ | { | ||||
if (blockingMessage != nullptr) | if (blockingMessage != nullptr) | ||||
{ | { | ||||
jassert (MessageManager::instance == nullptr || MessageManager::instance->currentThreadHasLockedMessageManager()); | |||||
MessageManager* const mm = MessageManager::instance; | |||||
jassert (mm == nullptr || mm->currentThreadHasLockedMessageManager()); | |||||
blockingMessage->releaseEvent.signal(); | blockingMessage->releaseEvent.signal(); | ||||
blockingMessage = nullptr; | blockingMessage = nullptr; | ||||
if (MessageManager::instance != nullptr) | |||||
if (mm != nullptr) | |||||
{ | { | ||||
MessageManager::instance->threadWithLock = 0; | |||||
MessageManager::instance->lockingLock.exit(); | |||||
mm->threadWithLock = 0; | |||||
mm->lockingLock.exit(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -177,7 +177,8 @@ private: | |||||
SortedSet <const MessageListener*> messageListeners; | SortedSet <const MessageListener*> messageListeners; | ||||
ScopedPointer <ActionBroadcaster> broadcaster; | ScopedPointer <ActionBroadcaster> broadcaster; | ||||
friend class JUCEApplication; | |||||
class QuitMessage; | |||||
friend class QuitMessage; | |||||
bool quitMessagePosted, quitMessageReceived; | bool quitMessagePosted, quitMessageReceived; | ||||
Thread::ThreadID messageThreadId; | Thread::ThreadID messageThreadId; | ||||
@@ -185,7 +186,7 @@ private: | |||||
Thread::ThreadID volatile threadWithLock; | Thread::ThreadID volatile threadWithLock; | ||||
CriticalSection lockingLock; | CriticalSection lockingLock; | ||||
void postMessageToQueue (Message* message); | |||||
void postMessageToQueue (Message*); | |||||
static bool postMessageToSystemQueue (Message*); | static bool postMessageToSystemQueue (Message*); | ||||
static void* exitModalLoopCallback (void*); | static void* exitModalLoopCallback (void*); | ||||
static void doPlatformSpecificInitialisation(); | static void doPlatformSpecificInitialisation(); | ||||
@@ -50,45 +50,6 @@ JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, deliverMessage, void, (jobje | |||||
message->decReferenceCount(); | message->decReferenceCount(); | ||||
} | } | ||||
//============================================================================== | |||||
class AsyncFunctionCaller : public AsyncUpdater | |||||
{ | |||||
public: | |||||
static void* call (MessageCallbackFunction* func_, void* parameter_) | |||||
{ | |||||
if (MessageManager::getInstance()->isThisTheMessageThread()) | |||||
return func_ (parameter_); | |||||
AsyncFunctionCaller caller (func_, parameter_); | |||||
caller.triggerAsyncUpdate(); | |||||
caller.finished.wait(); | |||||
return caller.result; | |||||
} | |||||
void handleAsyncUpdate() | |||||
{ | |||||
result = (*func) (parameter); | |||||
finished.signal(); | |||||
} | |||||
private: | |||||
WaitableEvent finished; | |||||
MessageCallbackFunction* func; | |||||
void* parameter; | |||||
void* volatile result; | |||||
AsyncFunctionCaller (MessageCallbackFunction* func_, void* parameter_) | |||||
: result (nullptr), func (func_), parameter (parameter_) | |||||
{} | |||||
JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCaller); | |||||
}; | |||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter) | |||||
{ | |||||
return AsyncFunctionCaller::call (func, parameter); | |||||
} | |||||
//============================================================================== | //============================================================================== | ||||
void MessageManager::broadcastMessage (const String&) | void MessageManager::broadcastMessage (const String&) | ||||
{ | { | ||||
@@ -23,52 +23,6 @@ | |||||
============================================================================== | ============================================================================== | ||||
*/ | */ | ||||
struct CallbackMessagePayload | |||||
{ | |||||
MessageCallbackFunction* function; | |||||
void* parameter; | |||||
void* volatile result; | |||||
bool volatile hasBeenExecuted; | |||||
}; | |||||
} // (juce namespace) | |||||
//============================================================================== | |||||
@interface JuceCustomMessageHandler : NSObject | |||||
{ | |||||
} | |||||
- (void) performCallback: (id) info; | |||||
@end | |||||
//============================================================================== | |||||
@implementation JuceCustomMessageHandler | |||||
- (void) performCallback: (id) info | |||||
{ | |||||
if ([info isKindOfClass: [NSData class]]) | |||||
{ | |||||
juce::CallbackMessagePayload* pl = (juce::CallbackMessagePayload*) [((NSData*) info) bytes]; | |||||
if (pl != nullptr) | |||||
{ | |||||
pl->result = (*pl->function) (pl->parameter); | |||||
pl->hasBeenExecuted = true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
jassertfalse; // should never get here! | |||||
} | |||||
} | |||||
@end | |||||
//============================================================================== | |||||
namespace juce | |||||
{ | |||||
void MessageManager::runDispatchLoop() | void MessageManager::runDispatchLoop() | ||||
{ | { | ||||
jassert (isThisTheMessageThread()); // must only be called by the message thread | jassert (isThisTheMessageThread()); // must only be called by the message thread | ||||
@@ -146,36 +100,3 @@ bool MessageManager::postMessageToSystemQueue (Message* message) | |||||
void MessageManager::broadcastMessage (const String& value) | void MessageManager::broadcastMessage (const String& value) | ||||
{ | { | ||||
} | } | ||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | |||||
{ | |||||
if (isThisTheMessageThread()) | |||||
{ | |||||
return (*callback) (data); | |||||
} | |||||
else | |||||
{ | |||||
jassert (dispatcher != nullptr); // 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.. | |||||
jassert (! MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | |||||
JUCE_AUTORELEASEPOOL | |||||
CallbackMessagePayload cmp; | |||||
cmp.function = callback; | |||||
cmp.parameter = data; | |||||
cmp.result = 0; | |||||
cmp.hasBeenExecuted = false; | |||||
[dispatcher->juceCustomMessageHandler performSelectorOnMainThread: @selector (performCallback:) | |||||
withObject: [NSData dataWithBytesNoCopy: &cmp | |||||
length: sizeof (cmp) | |||||
freeWhenDone: NO] | |||||
waitUntilDone: YES]; | |||||
return cmp.result; | |||||
} | |||||
} |
@@ -360,49 +360,6 @@ void MessageManager::broadcastMessage (const String& value) | |||||
/* TODO */ | /* TODO */ | ||||
} | } | ||||
//============================================================================== | |||||
class AsyncFunctionCaller : public AsyncUpdater | |||||
{ | |||||
public: | |||||
static void* call (MessageCallbackFunction* func_, void* parameter_) | |||||
{ | |||||
if (MessageManager::getInstance()->isThisTheMessageThread()) | |||||
return func_ (parameter_); | |||||
AsyncFunctionCaller caller (func_, parameter_); | |||||
caller.triggerAsyncUpdate(); | |||||
caller.finished.wait(); | |||||
return caller.result; | |||||
} | |||||
void handleAsyncUpdate() | |||||
{ | |||||
result = (*func) (parameter); | |||||
finished.signal(); | |||||
} | |||||
private: | |||||
WaitableEvent finished; | |||||
MessageCallbackFunction* func; | |||||
void* parameter; | |||||
void* volatile result; | |||||
AsyncFunctionCaller (MessageCallbackFunction* func_, void* parameter_) | |||||
: result (nullptr), func (func_), parameter (parameter_) | |||||
{} | |||||
JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCaller); | |||||
}; | |||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter) | |||||
{ | |||||
if (LinuxErrorHandling::errorOccurred) | |||||
return nullptr; | |||||
return AsyncFunctionCaller::call (func, parameter); | |||||
} | |||||
// this function expects that it will NEVER be called simultaneously for two concurrent threads | // this function expects that it will NEVER be called simultaneously for two concurrent threads | ||||
bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) | bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) | ||||
{ | { | ||||
@@ -91,20 +91,6 @@ public: | |||||
(*appFocusChangeCallback)(); | (*appFocusChangeCallback)(); | ||||
} | } | ||||
struct CallbackMessagePayload | |||||
{ | |||||
MessageCallbackFunction* function; | |||||
void* parameter; | |||||
void* volatile result; | |||||
bool volatile hasBeenExecuted; | |||||
}; | |||||
virtual void performCallback (CallbackMessagePayload* pl) | |||||
{ | |||||
pl->result = (*pl->function) (pl->parameter); | |||||
pl->hasBeenExecuted = true; | |||||
} | |||||
virtual void deleteSelf() | virtual void deleteSelf() | ||||
{ | { | ||||
delete this; | delete this; | ||||
@@ -159,7 +145,6 @@ using namespace juce; | |||||
- (void) applicationDidBecomeActive: (NSNotification*) aNotification; | - (void) applicationDidBecomeActive: (NSNotification*) aNotification; | ||||
- (void) applicationDidResignActive: (NSNotification*) aNotification; | - (void) applicationDidResignActive: (NSNotification*) aNotification; | ||||
- (void) applicationWillUnhide: (NSNotification*) aNotification; | - (void) applicationWillUnhide: (NSNotification*) aNotification; | ||||
- (void) performCallback: (id) info; | |||||
- (void) broadcastMessageCallback: (NSNotification*) info; | - (void) broadcastMessageCallback: (NSNotification*) info; | ||||
- (void) dummyMethod; | - (void) dummyMethod; | ||||
@end | @end | ||||
@@ -261,22 +246,6 @@ using namespace juce; | |||||
redirector->focusChanged(); | redirector->focusChanged(); | ||||
} | } | ||||
- (void) performCallback: (id) info | |||||
{ | |||||
if ([info isKindOfClass: [NSData class]]) | |||||
{ | |||||
AppDelegateRedirector::CallbackMessagePayload* pl | |||||
= (AppDelegateRedirector::CallbackMessagePayload*) [((NSData*) info) bytes]; | |||||
if (pl != nullptr) | |||||
redirector->performCallback (pl); | |||||
} | |||||
else | |||||
{ | |||||
jassertfalse; // should never get here! | |||||
} | |||||
} | |||||
- (void) broadcastMessageCallback: (NSNotification*) n | - (void) broadcastMessageCallback: (NSNotification*) n | ||||
{ | { | ||||
NSDictionary* dict = (NSDictionary*) [n userInfo]; | NSDictionary* dict = (NSDictionary*) [n userInfo]; | ||||
@@ -406,34 +375,3 @@ void MessageManager::broadcastMessage (const String& message) | |||||
object: nil | object: nil | ||||
userInfo: info]; | userInfo: info]; | ||||
} | } | ||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* data) | |||||
{ | |||||
if (isThisTheMessageThread()) | |||||
{ | |||||
return (*callback) (data); | |||||
} | |||||
else | |||||
{ | |||||
// 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.. | |||||
jassert (! MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | |||||
JUCE_AUTORELEASEPOOL | |||||
AppDelegateRedirector::CallbackMessagePayload cmp; | |||||
cmp.function = callback; | |||||
cmp.parameter = data; | |||||
cmp.result = 0; | |||||
cmp.hasBeenExecuted = false; | |||||
[juceAppDelegate performSelectorOnMainThread: @selector (performCallback:) | |||||
withObject: [NSData dataWithBytesNoCopy: &cmp | |||||
length: sizeof (cmp) | |||||
freeWhenDone: NO] | |||||
waitUntilDone: YES]; | |||||
return cmp.result; | |||||
} | |||||
} |
@@ -33,7 +33,6 @@ namespace WindowsMessageHelpers | |||||
{ | { | ||||
const unsigned int specialId = WM_APP + 0x4400; | const unsigned int specialId = WM_APP + 0x4400; | ||||
const unsigned int broadcastId = WM_APP + 0x4403; | const unsigned int broadcastId = WM_APP + 0x4403; | ||||
const unsigned int specialCallbackId = WM_APP + 0x4402; | |||||
const TCHAR messageWindowName[] = _T("JUCEWindow"); | const TCHAR messageWindowName[] = _T("JUCEWindow"); | ||||
ScopedPointer<HiddenMessageWindow> messageWindow; | ScopedPointer<HiddenMessageWindow> messageWindow; | ||||
@@ -45,12 +44,7 @@ namespace WindowsMessageHelpers | |||||
{ | { | ||||
if (h == juce_messageWindowHandle) | if (h == juce_messageWindowHandle) | ||||
{ | { | ||||
if (message == specialCallbackId) | |||||
{ | |||||
MessageCallbackFunction* const func = (MessageCallbackFunction*) wParam; | |||||
return (LRESULT) (*func) ((void*) lParam); | |||||
} | |||||
else if (message == specialId) | |||||
if (message == specialId) | |||||
{ | { | ||||
// these are trapped early in the dispatch call, but must also be checked | // these are trapped early in the dispatch call, but must also be checked | ||||
// here in case there are windows modal dialog boxes doing their own | // here in case there are windows modal dialog boxes doing their own | ||||
@@ -142,26 +136,6 @@ bool MessageManager::postMessageToSystemQueue (Message* message) | |||||
return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::specialId, 0, (LPARAM) message) != 0; | return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::specialId, 0, (LPARAM) message) != 0; | ||||
} | } | ||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData) | |||||
{ | |||||
if (MessageManager::getInstance()->isThisTheMessageThread()) | |||||
{ | |||||
return (*callback) (userData); | |||||
} | |||||
else | |||||
{ | |||||
// If a thread has a MessageManagerLock and then tries to call this method, it'll | |||||
// deadlock because the message manager is blocked from running, and can't | |||||
// call your function.. | |||||
jassert (! MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | |||||
return (void*) SendMessage (juce_messageWindowHandle, | |||||
WindowsMessageHelpers::specialCallbackId, | |||||
(WPARAM) callback, | |||||
(LPARAM) userData); | |||||
} | |||||
} | |||||
void MessageManager::broadcastMessage (const String& value) | void MessageManager::broadcastMessage (const String& value) | ||||
{ | { | ||||
Array<HWND> windows; | Array<HWND> windows; | ||||