diff --git a/modules/juce_events/native/juce_win32_Messaging.cpp b/modules/juce_events/native/juce_win32_Messaging.cpp index d9eabdf5cd..43c9152069 100644 --- a/modules/juce_events/native/juce_win32_Messaging.cpp +++ b/modules/juce_events/native/juce_win32_Messaging.cpp @@ -25,40 +25,164 @@ namespace juce extern HWND juce_messageWindowHandle; +#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity + bool juce_isRunningInUnity(); +#endif + +#if JUCE_MODULE_AVAILABLE_juce_gui_extra + LRESULT juce_offerEventToActiveXControl (::MSG&); +#endif + using CheckEventBlockedByModalComps = bool (*)(const MSG&); CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr; using SettingChangeCallbackFunc = void (*)(void); SettingChangeCallbackFunc settingChangeCallback = nullptr; -#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity - bool juce_isRunningInUnity(); -#endif - //============================================================================== -namespace WindowsMessageHelpers +class InternalMessageQueue { - const unsigned int customMessageID = WM_USER + 123; - const unsigned int broadcastMessageMagicNumber = 0xc403; - - const TCHAR messageWindowName[] = _T("JUCEWindow"); - std::unique_ptr messageWindow; - - void dispatchMessageFromLParam (LPARAM lParam) +public: + InternalMessageQueue() { - if (auto message = reinterpret_cast (lParam)) - { - JUCE_TRY - { - message->messageCallback(); - } - JUCE_CATCH_EXCEPTION + messageWindow = std::make_unique (messageWindowName, (WNDPROC) messageWndProc); + juce_messageWindowHandle = messageWindow->getHWND(); + } - message->decReferenceCount(); + ~InternalMessageQueue() + { + juce_messageWindowHandle = 0; + clearSingletonInstance(); + } + + JUCE_DECLARE_SINGLETON (InternalMessageQueue, false) + + //============================================================================== + void broadcastMessage (const String& message) + { + auto localCopy = message; + + Array windows; + EnumWindows (&broadcastEnumWindowProc, (LPARAM) &windows); + + for (int i = windows.size(); --i >= 0;) + { + COPYDATASTRUCT data; + data.dwData = broadcastMessageMagicNumber; + data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType); + data.lpData = (void*) localCopy.toUTF32().getAddress(); + + DWORD_PTR result; + SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA, + (WPARAM) juce_messageWindowHandle, + (LPARAM) &data, + SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result); } } - BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam) + bool postMessage (MessageManager::MessageBase* message) + { + message->incReferenceCount(); + + #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity + if (juce_isRunningInUnity()) + return SendNotifyMessage (juce_messageWindowHandle, customMessageID, 0, (LPARAM) message) != 0; + #endif + + if (PostMessage (juce_messageWindowHandle, customMessageID, 0, (LPARAM) message) != 0) + return true; + + if (GetLastError() == ERROR_NOT_ENOUGH_QUOTA) + { + const ScopedLock sl (lock); + overflowQueue.add (message); + message->decReferenceCount(); + + return true; + } + + return false; + } + + bool dispatchNextMessage (bool returnIfNoPendingMessages) + { + MSG m; + + if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE) && overflowQueue.size() == 0) + return false; + + if (GetMessage (&m, (HWND) 0, 0, 0) >= 0) + { + #if JUCE_MODULE_AVAILABLE_juce_gui_extra + if (juce_offerEventToActiveXControl (m) != S_FALSE) + return true; + #endif + + if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle) + { + dispatchMessageFromLParam (m.lParam); + } + else if (m.message == WM_QUIT) + { + if (auto* app = JUCEApplicationBase::getInstance()) + app->systemRequestedQuit(); + } + else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m)) + { + if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN) + && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd)) + { + // if it's someone else's window being clicked on, and the focus is + // currently on a juce window, pass the kb focus over.. + auto currentFocus = GetFocus(); + + if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus)) + SetFocus (m.hwnd); + } + + TranslateMessage (&m); + DispatchMessage (&m); + } + } + + dispatchOverflowMessages(); + + return true; + } + +private: + //============================================================================== + static LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept + { + if (h == juce_messageWindowHandle) + { + if (message == customMessageID) + { + // (These are trapped early in our dispatch loop, but must also be checked + // here in case some 3rd-party code is running the dispatch loop). + dispatchMessageFromLParam (lParam); + + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + queue->dispatchOverflowMessages(); + + return 0; + } + + if (message == WM_COPYDATA) + { + handleBroadcastMessage (reinterpret_cast (lParam)); + return 0; + } + + if (message == WM_SETTINGCHANGE) + if (settingChangeCallback != nullptr) + settingChangeCallback(); + } + + return DefWindowProc (h, message, wParam, lParam); + } + + static BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam) { if (hwnd != juce_messageWindowHandle) { @@ -72,7 +196,21 @@ namespace WindowsMessageHelpers return TRUE; } - void handleBroadcastMessage (const COPYDATASTRUCT* data) + static void dispatchMessageFromLParam (LPARAM lParam) + { + if (auto message = reinterpret_cast (lParam)) + { + JUCE_TRY + { + message->messageCallback(); + } + JUCE_CATCH_EXCEPTION + + message->decReferenceCount(); + } + } + + static void handleBroadcastMessage (const COPYDATASTRUCT* data) { if (data != nullptr && data->dwData == broadcastMessageMagicNumber) { @@ -90,132 +228,74 @@ namespace WindowsMessageHelpers } } - //============================================================================== - LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept + void dispatchOverflowMessages() { - if (h == juce_messageWindowHandle) + const ScopedLock sl (lock); + + for (int i = 0; i < overflowQueue.size(); ++i) { - if (message == customMessageID) - { - // (These are trapped early in our dispatch loop, but must also be checked - // here in case some 3rd-party code is running the dispatch loop). - dispatchMessageFromLParam (lParam); - return 0; - } - - if (message == WM_COPYDATA) - { - handleBroadcastMessage (reinterpret_cast (lParam)); - return 0; - } - - if (message == WM_SETTINGCHANGE) - if (settingChangeCallback != nullptr) - settingChangeCallback(); + auto message = overflowQueue.getUnchecked (i); + message->incReferenceCount(); + dispatchMessageFromLParam ((LPARAM) message.get()); } - return DefWindowProc (h, message, wParam, lParam); + overflowQueue.clear(); } -} -#if JUCE_MODULE_AVAILABLE_juce_gui_extra -LRESULT juce_offerEventToActiveXControl (::MSG&); -#endif + //============================================================================== + static constexpr unsigned int customMessageID = WM_USER + 123; + static constexpr unsigned int broadcastMessageMagicNumber = 0xc403; + static const TCHAR messageWindowName[]; + + std::unique_ptr messageWindow; + + CriticalSection lock; + ReferenceCountedArray overflowQueue; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalMessageQueue) +}; + +JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue) + +const TCHAR InternalMessageQueue::messageWindowName[] = _T("JUCEWindow"); //============================================================================== bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) { - using namespace WindowsMessageHelpers; - MSG m; + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + return queue->dispatchNextMessage (returnIfNoPendingMessages); - if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE)) - return false; - - if (GetMessage (&m, (HWND) 0, 0, 0) >= 0) - { - #if JUCE_MODULE_AVAILABLE_juce_gui_extra - if (juce_offerEventToActiveXControl (m) != S_FALSE) - return true; - #endif - - if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle) - { - dispatchMessageFromLParam (m.lParam); - } - else if (m.message == WM_QUIT) - { - if (auto* app = JUCEApplicationBase::getInstance()) - app->systemRequestedQuit(); - } - else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m)) - { - if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN) - && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd)) - { - // if it's someone else's window being clicked on, and the focus is - // currently on a juce window, pass the kb focus over.. - auto currentFocus = GetFocus(); - - if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus)) - SetFocus (m.hwnd); - } - - TranslateMessage (&m); - DispatchMessage (&m); - } - } - - return true; + return false; } bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) { - message->incReferenceCount(); + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + { + queue->postMessage (message); + return true; + } - #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity - if (juce_isRunningInUnity()) - return SendNotifyMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0; - #endif - - return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0; + return false; } void MessageManager::broadcastMessage (const String& value) { - auto localCopy = value; - - Array windows; - EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows); - - for (int i = windows.size(); --i >= 0;) - { - COPYDATASTRUCT data; - data.dwData = WindowsMessageHelpers::broadcastMessageMagicNumber; - data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType); - data.lpData = (void*) localCopy.toUTF32().getAddress(); - - DWORD_PTR result; - SendMessageTimeout (windows.getUnchecked (i), WM_COPYDATA, - (WPARAM) juce_messageWindowHandle, - (LPARAM) &data, - SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result); - } + if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) + queue->broadcastMessage (value); } //============================================================================== void MessageManager::doPlatformSpecificInitialisation() { OleInitialize (0); - - using namespace WindowsMessageHelpers; - messageWindow.reset (new HiddenMessageWindow (messageWindowName, (WNDPROC) messageWndProc)); - juce_messageWindowHandle = messageWindow->getHWND(); + InternalMessageQueue::getInstance(); } void MessageManager::doPlatformSpecificShutdown() { - WindowsMessageHelpers::messageWindow = nullptr; - + InternalMessageQueue::deleteInstance(); OleUninitialize(); } diff --git a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp index 455ceb3990..242b5cd6db 100644 --- a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp @@ -56,7 +56,7 @@ extern void juce_repeatLastProcessPriority(); extern void juce_checkCurrentlyFocusedTopLevelWindow(); // in juce_TopLevelWindow.cpp extern bool juce_isRunningInWine(); -typedef bool (*CheckEventBlockedByModalComps) (const MSG&); +using CheckEventBlockedByModalComps = bool (*)(const MSG&); extern CheckEventBlockedByModalComps isEventBlockedByModalComps; static bool shouldDeactivateTitleBar = true; @@ -496,7 +496,7 @@ static double getGlobalDPI() #endif //============================================================================== -typedef void (*SettingChangeCallbackFunc) (void); +using SettingChangeCallbackFunc = void (*)(void); extern SettingChangeCallbackFunc settingChangeCallback; //==============================================================================