| @@ -41,6 +41,8 @@ public: | |||
| private: | |||
| AsyncUpdater& owner; | |||
| JUCE_DECLARE_NON_COPYABLE (AsyncUpdaterMessage); | |||
| }; | |||
| //============================================================================== | |||
| @@ -192,15 +192,12 @@ private: | |||
| //============================================================================== | |||
| 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 connectionLostInt(); | |||
| void deliverDataInt (const MemoryBlock& data); | |||
| void deliverDataInt (const MemoryBlock&); | |||
| bool readNextMessageInt(); | |||
| void run(); | |||
| @@ -32,16 +32,27 @@ CallbackMessage::~CallbackMessage() {} | |||
| 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; | |||
| @@ -103,13 +114,7 @@ void MessageManager::deliverMessage (Message* const message) | |||
| CallbackMessage* const callbackMessage = dynamic_cast <CallbackMessage*> (message); | |||
| if (callbackMessage != nullptr) | |||
| { | |||
| callbackMessage->messageCallback(); | |||
| } | |||
| else if (dynamic_cast <QuitMessage*> (message) != nullptr) | |||
| { | |||
| quitMessageReceived = true; | |||
| } | |||
| } | |||
| else if (messageListeners.contains (recipient)) | |||
| { | |||
| @@ -130,8 +135,7 @@ void MessageManager::runDispatchLoop() | |||
| void MessageManager::stopDispatchLoop() | |||
| { | |||
| postMessageToQueue (new QuitMessage()); | |||
| quitMessagePosted = true; | |||
| (new QuitMessage())->post(); | |||
| } | |||
| bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| @@ -161,6 +165,41 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| #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) | |||
| { | |||
| @@ -249,25 +288,27 @@ MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSi | |||
| bool MessageManagerLock::attemptLock (Thread* const threadToCheck, ThreadPoolJob* const job) | |||
| { | |||
| if (MessageManager::instance == nullptr) | |||
| MessageManager* const mm = MessageManager::instance; | |||
| if (mm == nullptr) | |||
| return false; | |||
| if (MessageManager::instance->currentThreadHasLockedMessageManager()) | |||
| if (mm->currentThreadHasLockedMessageManager()) | |||
| return true; | |||
| if (threadToCheck == nullptr && job == nullptr) | |||
| { | |||
| MessageManager::instance->lockingLock.enter(); | |||
| mm->lockingLock.enter(); | |||
| } | |||
| else | |||
| { | |||
| while (! MessageManager::instance->lockingLock.tryEnter()) | |||
| while (! mm->lockingLock.tryEnter()) | |||
| { | |||
| if ((threadToCheck != nullptr && threadToCheck->threadShouldExit()) | |||
| || (job != nullptr && job->shouldExit())) | |||
| return false; | |||
| Thread::sleep (1); | |||
| Thread::yield(); | |||
| } | |||
| } | |||
| @@ -281,14 +322,14 @@ bool MessageManagerLock::attemptLock (Thread* const threadToCheck, ThreadPoolJob | |||
| { | |||
| blockingMessage->releaseEvent.signal(); | |||
| blockingMessage = nullptr; | |||
| MessageManager::instance->lockingLock.exit(); | |||
| mm->lockingLock.exit(); | |||
| return false; | |||
| } | |||
| } | |||
| jassert (MessageManager::instance->threadWithLock == 0); | |||
| jassert (mm->threadWithLock == 0); | |||
| MessageManager::instance->threadWithLock = Thread::getCurrentThreadId(); | |||
| mm->threadWithLock = Thread::getCurrentThreadId(); | |||
| return true; | |||
| } | |||
| @@ -296,15 +337,17 @@ MessageManagerLock::~MessageManagerLock() noexcept | |||
| { | |||
| if (blockingMessage != nullptr) | |||
| { | |||
| jassert (MessageManager::instance == nullptr || MessageManager::instance->currentThreadHasLockedMessageManager()); | |||
| MessageManager* const mm = MessageManager::instance; | |||
| jassert (mm == nullptr || mm->currentThreadHasLockedMessageManager()); | |||
| blockingMessage->releaseEvent.signal(); | |||
| 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; | |||
| ScopedPointer <ActionBroadcaster> broadcaster; | |||
| friend class JUCEApplication; | |||
| class QuitMessage; | |||
| friend class QuitMessage; | |||
| bool quitMessagePosted, quitMessageReceived; | |||
| Thread::ThreadID messageThreadId; | |||
| @@ -185,7 +186,7 @@ private: | |||
| Thread::ThreadID volatile threadWithLock; | |||
| CriticalSection lockingLock; | |||
| void postMessageToQueue (Message* message); | |||
| void postMessageToQueue (Message*); | |||
| static bool postMessageToSystemQueue (Message*); | |||
| static void* exitModalLoopCallback (void*); | |||
| static void doPlatformSpecificInitialisation(); | |||
| @@ -50,45 +50,6 @@ JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, deliverMessage, void, (jobje | |||
| 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&) | |||
| { | |||
| @@ -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() | |||
| { | |||
| 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::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 */ | |||
| } | |||
| //============================================================================== | |||
| 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 | |||
| bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) | |||
| { | |||
| @@ -91,20 +91,6 @@ public: | |||
| (*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() | |||
| { | |||
| delete this; | |||
| @@ -159,7 +145,6 @@ using namespace juce; | |||
| - (void) applicationDidBecomeActive: (NSNotification*) aNotification; | |||
| - (void) applicationDidResignActive: (NSNotification*) aNotification; | |||
| - (void) applicationWillUnhide: (NSNotification*) aNotification; | |||
| - (void) performCallback: (id) info; | |||
| - (void) broadcastMessageCallback: (NSNotification*) info; | |||
| - (void) dummyMethod; | |||
| @end | |||
| @@ -261,22 +246,6 @@ using namespace juce; | |||
| 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 | |||
| { | |||
| NSDictionary* dict = (NSDictionary*) [n userInfo]; | |||
| @@ -406,34 +375,3 @@ void MessageManager::broadcastMessage (const String& message) | |||
| object: nil | |||
| 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 broadcastId = WM_APP + 0x4403; | |||
| const unsigned int specialCallbackId = WM_APP + 0x4402; | |||
| const TCHAR messageWindowName[] = _T("JUCEWindow"); | |||
| ScopedPointer<HiddenMessageWindow> messageWindow; | |||
| @@ -45,12 +44,7 @@ namespace WindowsMessageHelpers | |||
| { | |||
| 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 | |||
| // 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; | |||
| } | |||
| 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) | |||
| { | |||
| Array<HWND> windows; | |||