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