/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2015 - ROLI Ltd. Permission is granted to use this software under the terms of either: a) the GPL v2 (or any later version) b) the Affero GPL v3 Details of these licenses can be found at: www.gnu.org/licenses JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.juce.com for more information. ============================================================================== */ extern HWND juce_messageWindowHandle; typedef bool (*CheckEventBlockedByModalComps) (const MSG&); CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr; //============================================================================== namespace WindowsMessageHelpers { const unsigned int specialId = WM_APP + 0x4400; const unsigned int broadcastId = WM_APP + 0x4403; const TCHAR messageWindowName[] = _T("JUCEWindow"); ScopedPointer messageWindow; void dispatchMessageFromLParam (LPARAM lParam) { MessageManager::MessageBase* const message = reinterpret_cast (lParam); JUCE_TRY { message->messageCallback(); } JUCE_CATCH_EXCEPTION message->decReferenceCount(); } //============================================================================== LRESULT CALLBACK messageWndProc (HWND h, const UINT message, const WPARAM wParam, const LPARAM lParam) noexcept { if (h == juce_messageWindowHandle) { if (message == specialId) { // (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 == broadcastId) { const ScopedPointer messageString ((String*) lParam); MessageManager::getInstance()->deliverBroadcastMessage (*messageString); return 0; } if (message == WM_COPYDATA) { const COPYDATASTRUCT* const data = reinterpret_cast (lParam); if (data->dwData == broadcastId) { const String messageString (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData), data->cbData / sizeof (CharPointer_UTF32::CharType)); PostMessage (juce_messageWindowHandle, broadcastId, 0, (LPARAM) new String (messageString)); return 0; } } } return DefWindowProc (h, message, wParam, lParam); } BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam) { if (hwnd != juce_messageWindowHandle) reinterpret_cast*> (lParam)->add (hwnd); return TRUE; } } //============================================================================== bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages) { using namespace WindowsMessageHelpers; MSG m; if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE)) return false; if (GetMessage (&m, (HWND) 0, 0, 0) >= 0) { if (m.message == specialId && m.hwnd == juce_messageWindowHandle) { dispatchMessageFromLParam (m.lParam); } else if (m.message == WM_QUIT) { if (JUCEApplicationBase* const 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.. HWND currentFocus = GetFocus(); if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus)) SetFocus (m.hwnd); } TranslateMessage (&m); DispatchMessage (&m); } } return true; } bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) { message->incReferenceCount(); return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::specialId, 0, (LPARAM) message) != 0; } void MessageManager::broadcastMessage (const String& value) { Array windows; EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows); const String localCopy (value); COPYDATASTRUCT data; data.dwData = WindowsMessageHelpers::broadcastId; data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType); data.lpData = (void*) localCopy.toUTF32().getAddress(); for (int i = windows.size(); --i >= 0;) { HWND hwnd = windows.getUnchecked(i); TCHAR windowName[64] = { 0 }; // no need to read longer strings than this GetWindowText (hwnd, windowName, 63); if (String (windowName) == WindowsMessageHelpers::messageWindowName) { DWORD_PTR result; SendMessageTimeout (hwnd, WM_COPYDATA, (WPARAM) juce_messageWindowHandle, (LPARAM) &data, SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result); } } } //============================================================================== void MessageManager::doPlatformSpecificInitialisation() { OleInitialize (0); using namespace WindowsMessageHelpers; messageWindow = new HiddenMessageWindow (messageWindowName, (WNDPROC) messageWndProc); juce_messageWindowHandle = messageWindow->getHWND(); } void MessageManager::doPlatformSpecificShutdown() { WindowsMessageHelpers::messageWindow = nullptr; OleUninitialize(); } //============================================================================== struct MountedVolumeListChangeDetector::Pimpl : private DeviceChangeDetector { Pimpl (MountedVolumeListChangeDetector& d) : DeviceChangeDetector (L"MountedVolumeList"), owner (d) { File::findFileSystemRoots (lastVolumeList); } void systemDeviceChanged() override { Array newList; File::findFileSystemRoots (newList); if (lastVolumeList != newList) { lastVolumeList = newList; owner.mountedVolumeListChanged(); } } MountedVolumeListChangeDetector& owner; Array lastVolumeList; }; MountedVolumeListChangeDetector::MountedVolumeListChangeDetector() { pimpl = new Pimpl (*this); } MountedVolumeListChangeDetector::~MountedVolumeListChangeDetector() {}