The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 lines
7.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. extern HWND juce_messageWindowHandle;
  18. typedef bool (*CheckEventBlockedByModalComps) (const MSG&);
  19. CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr;
  20. //==============================================================================
  21. namespace WindowsMessageHelpers
  22. {
  23. const unsigned int specialId = WM_APP + 0x4400;
  24. const unsigned int broadcastId = WM_APP + 0x4403;
  25. const TCHAR messageWindowName[] = _T("JUCEWindow");
  26. ScopedPointer<HiddenMessageWindow> messageWindow;
  27. void dispatchMessageFromLParam (LPARAM lParam)
  28. {
  29. if (MessageManager::MessageBase* const message = reinterpret_cast<MessageManager::MessageBase*> (lParam))
  30. {
  31. JUCE_TRY
  32. {
  33. message->messageCallback();
  34. }
  35. JUCE_CATCH_EXCEPTION
  36. message->decReferenceCount();
  37. }
  38. }
  39. //==============================================================================
  40. LRESULT CALLBACK messageWndProc (HWND h, const UINT message, const WPARAM wParam, const LPARAM lParam) noexcept
  41. {
  42. if (h == juce_messageWindowHandle)
  43. {
  44. if (message == specialId)
  45. {
  46. // (These are trapped early in our dispatch loop, but must also be checked
  47. // here in case some 3rd-party code is running the dispatch loop).
  48. dispatchMessageFromLParam (lParam);
  49. return 0;
  50. }
  51. if (message == broadcastId)
  52. {
  53. if (String* const m = reinterpret_cast<String*> (lParam))
  54. {
  55. const ScopedPointer<String> messageString (m);
  56. MessageManager::getInstance()->deliverBroadcastMessage (*m);
  57. }
  58. return 0;
  59. }
  60. if (message == WM_COPYDATA)
  61. {
  62. if (const COPYDATASTRUCT* const data = reinterpret_cast<const COPYDATASTRUCT*> (lParam))
  63. {
  64. if (data->dwData == broadcastId)
  65. {
  66. const String messageString (CharPointer_UTF32 ((const CharPointer_UTF32::CharType*) data->lpData),
  67. data->cbData / sizeof (CharPointer_UTF32::CharType));
  68. PostMessage (juce_messageWindowHandle, broadcastId, 0, (LPARAM) new String (messageString));
  69. return 0;
  70. }
  71. }
  72. }
  73. }
  74. return DefWindowProc (h, message, wParam, lParam);
  75. }
  76. BOOL CALLBACK broadcastEnumWindowProc (HWND hwnd, LPARAM lParam)
  77. {
  78. if (hwnd != juce_messageWindowHandle)
  79. reinterpret_cast<Array<HWND>*> (lParam)->add (hwnd);
  80. return TRUE;
  81. }
  82. }
  83. //==============================================================================
  84. bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages)
  85. {
  86. using namespace WindowsMessageHelpers;
  87. MSG m;
  88. if (returnIfNoPendingMessages && ! PeekMessage (&m, (HWND) 0, 0, 0, PM_NOREMOVE))
  89. return false;
  90. if (GetMessage (&m, (HWND) 0, 0, 0) >= 0)
  91. {
  92. if (m.message == specialId && m.hwnd == juce_messageWindowHandle)
  93. {
  94. dispatchMessageFromLParam (m.lParam);
  95. }
  96. else if (m.message == WM_QUIT)
  97. {
  98. if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
  99. app->systemRequestedQuit();
  100. }
  101. else if (isEventBlockedByModalComps == nullptr || ! isEventBlockedByModalComps (m))
  102. {
  103. if ((m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN)
  104. && ! JuceWindowIdentifier::isJUCEWindow (m.hwnd))
  105. {
  106. // if it's someone else's window being clicked on, and the focus is
  107. // currently on a juce window, pass the kb focus over..
  108. HWND currentFocus = GetFocus();
  109. if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus))
  110. SetFocus (m.hwnd);
  111. }
  112. TranslateMessage (&m);
  113. DispatchMessage (&m);
  114. }
  115. }
  116. return true;
  117. }
  118. bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
  119. {
  120. message->incReferenceCount();
  121. return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::specialId, 0, (LPARAM) message) != 0;
  122. }
  123. void MessageManager::broadcastMessage (const String& value)
  124. {
  125. Array<HWND> windows;
  126. EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows);
  127. const String localCopy (value);
  128. COPYDATASTRUCT data;
  129. data.dwData = WindowsMessageHelpers::broadcastId;
  130. data.cbData = (localCopy.length() + 1) * sizeof (CharPointer_UTF32::CharType);
  131. data.lpData = (void*) localCopy.toUTF32().getAddress();
  132. for (int i = windows.size(); --i >= 0;)
  133. {
  134. HWND hwnd = windows.getUnchecked(i);
  135. TCHAR windowName[64] = { 0 }; // no need to read longer strings than this
  136. GetWindowText (hwnd, windowName, 63);
  137. if (String (windowName) == WindowsMessageHelpers::messageWindowName)
  138. {
  139. DWORD_PTR result;
  140. SendMessageTimeout (hwnd, WM_COPYDATA,
  141. (WPARAM) juce_messageWindowHandle,
  142. (LPARAM) &data,
  143. SMTO_BLOCK | SMTO_ABORTIFHUNG, 8000, &result);
  144. }
  145. }
  146. }
  147. //==============================================================================
  148. void MessageManager::doPlatformSpecificInitialisation()
  149. {
  150. OleInitialize (0);
  151. using namespace WindowsMessageHelpers;
  152. messageWindow = new HiddenMessageWindow (messageWindowName, (WNDPROC) messageWndProc);
  153. juce_messageWindowHandle = messageWindow->getHWND();
  154. }
  155. void MessageManager::doPlatformSpecificShutdown()
  156. {
  157. WindowsMessageHelpers::messageWindow = nullptr;
  158. OleUninitialize();
  159. }
  160. //==============================================================================
  161. struct MountedVolumeListChangeDetector::Pimpl : private DeviceChangeDetector
  162. {
  163. Pimpl (MountedVolumeListChangeDetector& d) : DeviceChangeDetector (L"MountedVolumeList"), owner (d)
  164. {
  165. File::findFileSystemRoots (lastVolumeList);
  166. }
  167. void systemDeviceChanged() override
  168. {
  169. Array<File> newList;
  170. File::findFileSystemRoots (newList);
  171. if (lastVolumeList != newList)
  172. {
  173. lastVolumeList = newList;
  174. owner.mountedVolumeListChanged();
  175. }
  176. }
  177. MountedVolumeListChangeDetector& owner;
  178. Array<File> lastVolumeList;
  179. };
  180. MountedVolumeListChangeDetector::MountedVolumeListChangeDetector() { pimpl = new Pimpl (*this); }
  181. MountedVolumeListChangeDetector::~MountedVolumeListChangeDetector() {}