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.

384 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../juce_core/basics/juce_StandardHeader.h"
  24. BEGIN_JUCE_NAMESPACE
  25. #include "juce_MessageManager.h"
  26. #include "juce_ActionListenerList.h"
  27. #include "../application/juce_Application.h"
  28. #include "../gui/components/juce_Component.h"
  29. #include "../../juce_core/threads/juce_Thread.h"
  30. #include "../../juce_core/basics/juce_Time.h"
  31. //==============================================================================
  32. // platform-specific functions..
  33. bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
  34. bool juce_postMessageToSystemQueue (void* message);
  35. //==============================================================================
  36. MessageManager* MessageManager::instance = 0;
  37. static const int quitMessageId = 0xfffff321;
  38. MessageManager::MessageManager() throw()
  39. : broadcastListeners (0),
  40. quitMessagePosted (false),
  41. quitMessageReceived (false),
  42. useMaximumForceWhenQuitting (true),
  43. messageCounter (0),
  44. lastMessageCounter (-1),
  45. isInMessageDispatcher (0),
  46. needToGetRidOfWaitCursor (false),
  47. timeBeforeWaitCursor (0),
  48. lastActivityCheckOkTime (0)
  49. {
  50. currentLockingThreadId = messageThreadId = Thread::getCurrentThreadId();
  51. }
  52. MessageManager::~MessageManager() throw()
  53. {
  54. jassert (instance == this);
  55. instance = 0;
  56. deleteAndZero (broadcastListeners);
  57. doPlatformSpecificShutdown();
  58. }
  59. MessageManager* MessageManager::getInstance() throw()
  60. {
  61. if (instance == 0)
  62. {
  63. instance = new MessageManager();
  64. doPlatformSpecificInitialisation();
  65. instance->setTimeBeforeShowingWaitCursor (500);
  66. }
  67. return instance;
  68. }
  69. void MessageManager::postMessageToQueue (Message* const message)
  70. {
  71. if (quitMessagePosted || ! juce_postMessageToSystemQueue (message))
  72. delete message;
  73. }
  74. //==============================================================================
  75. // not for public use..
  76. void MessageManager::deliverMessage (void* message)
  77. {
  78. const MessageManagerLock lock;
  79. Message* const m = (Message*) message;
  80. MessageListener* const recipient = m->messageRecipient;
  81. if (messageListeners.contains (recipient))
  82. {
  83. JUCE_TRY
  84. {
  85. recipient->handleMessage (*m);
  86. }
  87. JUCE_CATCH_EXCEPTION
  88. if (needToGetRidOfWaitCursor)
  89. {
  90. needToGetRidOfWaitCursor = false;
  91. MouseCursor::hideWaitCursor();
  92. }
  93. ++messageCounter;
  94. }
  95. else if (recipient == 0 && m->intParameter1 == quitMessageId)
  96. {
  97. quitMessageReceived = true;
  98. useMaximumForceWhenQuitting = (m->intParameter2 != 0);
  99. }
  100. delete m;
  101. }
  102. //==============================================================================
  103. bool MessageManager::dispatchNextMessage (const bool returnImmediatelyIfNoMessages,
  104. bool* const wasAMessageDispatched)
  105. {
  106. if (quitMessageReceived)
  107. {
  108. if (wasAMessageDispatched != 0)
  109. *wasAMessageDispatched = false;
  110. return false;
  111. }
  112. ++isInMessageDispatcher;
  113. bool result = false;
  114. JUCE_TRY
  115. {
  116. result = juce_dispatchNextMessageOnSystemQueue (returnImmediatelyIfNoMessages);
  117. if (wasAMessageDispatched != 0)
  118. *wasAMessageDispatched = result;
  119. if (instance == 0)
  120. return false;
  121. }
  122. JUCE_CATCH_EXCEPTION
  123. --isInMessageDispatcher;
  124. ++messageCounter;
  125. return result || ! returnImmediatelyIfNoMessages;
  126. }
  127. void MessageManager::dispatchPendingMessages (int maxNumberOfMessagesToDispatch)
  128. {
  129. jassert (isThisTheMessageThread()); // must only be called by the message thread
  130. while (--maxNumberOfMessagesToDispatch >= 0 && ! quitMessageReceived)
  131. {
  132. ++isInMessageDispatcher;
  133. bool carryOn = false;
  134. JUCE_TRY
  135. {
  136. carryOn = juce_dispatchNextMessageOnSystemQueue (true);
  137. }
  138. JUCE_CATCH_EXCEPTION
  139. --isInMessageDispatcher;
  140. ++messageCounter;
  141. if (! carryOn)
  142. break;
  143. }
  144. }
  145. bool MessageManager::runDispatchLoop()
  146. {
  147. jassert (isThisTheMessageThread()); // must only be called by the message thread
  148. while (dispatchNextMessage())
  149. {
  150. }
  151. return useMaximumForceWhenQuitting;
  152. }
  153. //==============================================================================
  154. void MessageManager::postQuitMessage (const bool useMaximumForce)
  155. {
  156. if (! quitMessagePosted)
  157. {
  158. Message* const m = new Message (quitMessageId, (useMaximumForce) ? 1 : 0, 0, 0);
  159. m->messageRecipient = 0;
  160. if (! juce_postMessageToSystemQueue (m))
  161. delete m;
  162. quitMessagePosted = true;
  163. }
  164. }
  165. bool MessageManager::hasQuitMessageBeenPosted() const
  166. {
  167. return quitMessagePosted;
  168. }
  169. //==============================================================================
  170. void MessageManager::deliverBroadcastMessage (const String& value)
  171. {
  172. if (broadcastListeners == 0)
  173. broadcastListeners = new ActionListenerList();
  174. broadcastListeners->sendActionMessage (value);
  175. }
  176. void MessageManager::registerBroadcastListener (ActionListener* listener)
  177. {
  178. if (broadcastListeners == 0)
  179. broadcastListeners = new ActionListenerList();
  180. broadcastListeners->addActionListener (listener);
  181. }
  182. void MessageManager::deregisterBroadcastListener (ActionListener* listener)
  183. {
  184. if (broadcastListeners == 0)
  185. broadcastListeners = new ActionListenerList();
  186. broadcastListeners->removeActionListener (listener);
  187. }
  188. //==============================================================================
  189. // This gets called occasionally by the timer thread (to save using an extra thread
  190. // for it).
  191. void MessageManager::inactivityCheckCallback()
  192. {
  193. if (instance != 0)
  194. instance->inactivityCheckCallbackInt();
  195. }
  196. void MessageManager::inactivityCheckCallbackInt()
  197. {
  198. const unsigned int now = Time::getApproximateMillisecondCounter();
  199. if (isInMessageDispatcher > 0
  200. && lastMessageCounter == messageCounter
  201. && timeBeforeWaitCursor > 0
  202. && lastActivityCheckOkTime > 0
  203. && ! ModifierKeys::getCurrentModifiersRealtime().isAnyMouseButtonDown())
  204. {
  205. if (now >= lastActivityCheckOkTime + timeBeforeWaitCursor
  206. && ! needToGetRidOfWaitCursor)
  207. {
  208. // been in the same message call too long..
  209. MouseCursor::showWaitCursor();
  210. needToGetRidOfWaitCursor = true;
  211. }
  212. }
  213. else
  214. {
  215. lastActivityCheckOkTime = now;
  216. lastMessageCounter = messageCounter;
  217. }
  218. }
  219. void MessageManager::delayWaitCursor()
  220. {
  221. if (instance != 0)
  222. {
  223. instance->messageCounter++;
  224. if (instance->needToGetRidOfWaitCursor)
  225. {
  226. instance->needToGetRidOfWaitCursor = false;
  227. MouseCursor::hideWaitCursor();
  228. }
  229. }
  230. }
  231. void MessageManager::setTimeBeforeShowingWaitCursor (const int millisecs)
  232. {
  233. // if this is a bit too small you'll get a lot of unwanted hourglass cursors..
  234. jassert (millisecs <= 0 || millisecs > 200);
  235. timeBeforeWaitCursor = millisecs;
  236. if (millisecs > 0)
  237. startTimer (millisecs / 2); // (see timerCallback() for explanation of this)
  238. else
  239. stopTimer();
  240. }
  241. void MessageManager::timerCallback()
  242. {
  243. // dummy callback - the message manager is just a Timer to ensure that there are always
  244. // some events coming in - otherwise it'll show the egg-timer/beachball-of-death.
  245. ++messageCounter;
  246. }
  247. int MessageManager::getTimeBeforeShowingWaitCursor() const
  248. {
  249. return timeBeforeWaitCursor;
  250. }
  251. bool MessageManager::isThisTheMessageThread() const
  252. {
  253. return Thread::getCurrentThreadId() == messageThreadId;
  254. }
  255. void MessageManager::setCurrentMessageThread (const int threadId)
  256. {
  257. messageThreadId = threadId;
  258. }
  259. bool MessageManager::currentThreadHasLockedMessageManager() const
  260. {
  261. return Thread::getCurrentThreadId() == currentLockingThreadId;
  262. }
  263. //==============================================================================
  264. MessageManagerLock::MessageManagerLock() throw()
  265. : locked (true)
  266. {
  267. if (MessageManager::instance != 0)
  268. {
  269. MessageManager::instance->messageDispatchLock.enter();
  270. lastLockingThreadId = MessageManager::instance->currentLockingThreadId;
  271. MessageManager::instance->currentLockingThreadId = Thread::getCurrentThreadId();
  272. }
  273. }
  274. MessageManagerLock::MessageManagerLock (Thread* const thread) throw()
  275. {
  276. jassert (thread != 0); // This will only work if you give it a valid thread!
  277. if (MessageManager::instance != 0)
  278. {
  279. for (;;)
  280. {
  281. if (MessageManager::instance->messageDispatchLock.tryEnter())
  282. {
  283. locked = true;
  284. lastLockingThreadId = MessageManager::instance->currentLockingThreadId;
  285. MessageManager::instance->currentLockingThreadId = Thread::getCurrentThreadId();
  286. break;
  287. }
  288. if (thread != 0 && thread->threadShouldExit())
  289. {
  290. locked = false;
  291. break;
  292. }
  293. Thread::sleep (1);
  294. }
  295. }
  296. }
  297. MessageManagerLock::~MessageManagerLock() throw()
  298. {
  299. if (locked && MessageManager::instance != 0)
  300. {
  301. MessageManager::instance->currentLockingThreadId = lastLockingThreadId;
  302. MessageManager::instance->messageDispatchLock.exit();
  303. }
  304. }
  305. END_JUCE_NAMESPACE