PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/juce/src/events/juce_MessageManager.cpp

http://juced.googlecode.com/
C++ | 343 lines | 236 code | 59 blank | 48 comment | 56 complexity | eb25e111e45bab0e4c01f75231a5169d MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-2.0
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_MessageManager.h"
  21. #include "juce_ActionListenerList.h"
  22. #include "../application/juce_Application.h"
  23. #include "../gui/components/juce_Component.h"
  24. #include "../threads/juce_Thread.h"
  25. #include "../threads/juce_ScopedLock.h"
  26. #include "../core/juce_Time.h"
  27. //==============================================================================
  28. // platform-specific functions..
  29. bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
  30. bool juce_postMessageToSystemQueue (void* message);
  31. //==============================================================================
  32. MessageManager* MessageManager::instance = 0;
  33. static const int quitMessageId = 0xfffff321;
  34. MessageManager::MessageManager() throw()
  35. : quitMessagePosted (false),
  36. quitMessageReceived (false),
  37. threadWithLock (0)
  38. {
  39. messageThreadId = Thread::getCurrentThreadId();
  40. }
  41. MessageManager::~MessageManager() throw()
  42. {
  43. broadcastListeners = 0;
  44. doPlatformSpecificShutdown();
  45. jassert (instance == this);
  46. instance = 0; // do this last in case this instance is still needed by doPlatformSpecificShutdown()
  47. }
  48. MessageManager* MessageManager::getInstance() throw()
  49. {
  50. if (instance == 0)
  51. {
  52. instance = new MessageManager();
  53. doPlatformSpecificInitialisation();
  54. }
  55. return instance;
  56. }
  57. void MessageManager::postMessageToQueue (Message* const message)
  58. {
  59. if (quitMessagePosted || ! juce_postMessageToSystemQueue (message))
  60. delete message;
  61. }
  62. //==============================================================================
  63. CallbackMessage::CallbackMessage() throw() {}
  64. CallbackMessage::~CallbackMessage() throw() {}
  65. void CallbackMessage::post()
  66. {
  67. if (MessageManager::instance != 0)
  68. MessageManager::instance->postCallbackMessage (this);
  69. }
  70. void MessageManager::postCallbackMessage (Message* const message)
  71. {
  72. message->messageRecipient = 0;
  73. postMessageToQueue (message);
  74. }
  75. //==============================================================================
  76. // not for public use..
  77. void MessageManager::deliverMessage (void* message)
  78. {
  79. const ScopedPointer <Message> m ((Message*) message);
  80. MessageListener* const recipient = m->messageRecipient;
  81. JUCE_TRY
  82. {
  83. if (messageListeners.contains (recipient))
  84. {
  85. recipient->handleMessage (*m);
  86. }
  87. else if (recipient == 0)
  88. {
  89. if (m->intParameter1 == quitMessageId)
  90. {
  91. quitMessageReceived = true;
  92. }
  93. else
  94. {
  95. CallbackMessage* const cm = dynamic_cast <CallbackMessage*> ((Message*) m);
  96. if (cm != 0)
  97. cm->messageCallback();
  98. }
  99. }
  100. }
  101. JUCE_CATCH_EXCEPTION
  102. }
  103. //==============================================================================
  104. #if ! (JUCE_MAC || JUCE_IPHONE)
  105. void MessageManager::runDispatchLoop()
  106. {
  107. jassert (isThisTheMessageThread()); // must only be called by the message thread
  108. runDispatchLoopUntil (-1);
  109. }
  110. void MessageManager::stopDispatchLoop()
  111. {
  112. Message* const m = new Message (quitMessageId, 0, 0, 0);
  113. m->messageRecipient = 0;
  114. postMessageToQueue (m);
  115. quitMessagePosted = true;
  116. }
  117. bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
  118. {
  119. jassert (isThisTheMessageThread()); // must only be called by the message thread
  120. const int64 endTime = Time::currentTimeMillis() + millisecondsToRunFor;
  121. while ((millisecondsToRunFor < 0 || endTime > Time::currentTimeMillis())
  122. && ! quitMessageReceived)
  123. {
  124. JUCE_TRY
  125. {
  126. if (! juce_dispatchNextMessageOnSystemQueue (millisecondsToRunFor >= 0))
  127. {
  128. const int msToWait = (int) (endTime - Time::currentTimeMillis());
  129. if (msToWait > 0)
  130. Thread::sleep (jmin (5, msToWait));
  131. }
  132. }
  133. JUCE_CATCH_EXCEPTION
  134. }
  135. return ! quitMessageReceived;
  136. }
  137. #endif
  138. //==============================================================================
  139. void MessageManager::deliverBroadcastMessage (const String& value)
  140. {
  141. if (broadcastListeners != 0)
  142. broadcastListeners->sendActionMessage (value);
  143. }
  144. void MessageManager::registerBroadcastListener (ActionListener* const listener) throw()
  145. {
  146. if (broadcastListeners == 0)
  147. broadcastListeners = new ActionListenerList();
  148. broadcastListeners->addActionListener (listener);
  149. }
  150. void MessageManager::deregisterBroadcastListener (ActionListener* const listener) throw()
  151. {
  152. if (broadcastListeners != 0)
  153. broadcastListeners->removeActionListener (listener);
  154. }
  155. //==============================================================================
  156. bool MessageManager::isThisTheMessageThread() const throw()
  157. {
  158. return Thread::getCurrentThreadId() == messageThreadId;
  159. }
  160. void MessageManager::setCurrentMessageThread (const Thread::ThreadID threadId) throw()
  161. {
  162. messageThreadId = threadId;
  163. }
  164. bool MessageManager::currentThreadHasLockedMessageManager() const throw()
  165. {
  166. const Thread::ThreadID thisThread = Thread::getCurrentThreadId();
  167. return thisThread == messageThreadId || thisThread == threadWithLock;
  168. }
  169. //==============================================================================
  170. //==============================================================================
  171. /* The only safe way to lock the message thread while another thread does
  172. some work is by posting a special message, whose purpose is to tie up the event
  173. loop until the other thread has finished its business.
  174. Any other approach can get horribly deadlocked if the OS uses its own hidden locks which
  175. get locked before making an event callback, because if the same OS lock gets indirectly
  176. accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
  177. in Cocoa).
  178. */
  179. class SharedLockingEvents : public ReferenceCountedObject
  180. {
  181. public:
  182. SharedLockingEvents() throw() {}
  183. ~SharedLockingEvents() {}
  184. /* This class just holds a couple of events to communicate between the MMLockMessage
  185. and the MessageManagerLock. Because both of these objects may be deleted at any time,
  186. this shared data must be kept in a separate, ref-counted container. */
  187. WaitableEvent lockedEvent, releaseEvent;
  188. };
  189. class MMLockMessage : public CallbackMessage
  190. {
  191. public:
  192. MMLockMessage (SharedLockingEvents* const events_) throw()
  193. : events (events_)
  194. {}
  195. ~MMLockMessage() throw() {}
  196. ReferenceCountedObjectPtr <SharedLockingEvents> events;
  197. void messageCallback()
  198. {
  199. events->lockedEvent.signal();
  200. events->releaseEvent.wait();
  201. }
  202. juce_UseDebuggingNewOperator
  203. MMLockMessage (const MMLockMessage&);
  204. const MMLockMessage& operator= (const MMLockMessage&);
  205. };
  206. //==============================================================================
  207. MessageManagerLock::MessageManagerLock (Thread* const threadToCheck) throw()
  208. : locked (false),
  209. needsUnlocking (false)
  210. {
  211. init (threadToCheck, 0);
  212. }
  213. MessageManagerLock::MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) throw()
  214. : locked (false),
  215. needsUnlocking (false)
  216. {
  217. init (0, jobToCheckForExitSignal);
  218. }
  219. void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const job) throw()
  220. {
  221. if (MessageManager::instance != 0)
  222. {
  223. if (MessageManager::instance->currentThreadHasLockedMessageManager())
  224. {
  225. locked = true; // either we're on the message thread, or this is a re-entrant call.
  226. }
  227. else
  228. {
  229. if (threadToCheck == 0 && job == 0)
  230. {
  231. MessageManager::instance->lockingLock.enter();
  232. }
  233. else
  234. {
  235. while (! MessageManager::instance->lockingLock.tryEnter())
  236. {
  237. if ((threadToCheck != 0 && threadToCheck->threadShouldExit())
  238. || (job != 0 && job->shouldExit()))
  239. return;
  240. Thread::sleep (1);
  241. }
  242. }
  243. SharedLockingEvents* const events = new SharedLockingEvents();
  244. sharedEvents = events;
  245. events->incReferenceCount();
  246. (new MMLockMessage (events))->post();
  247. while (! events->lockedEvent.wait (50))
  248. {
  249. if ((threadToCheck != 0 && threadToCheck->threadShouldExit())
  250. || (job != 0 && job->shouldExit()))
  251. {
  252. events->releaseEvent.signal();
  253. events->decReferenceCount();
  254. MessageManager::instance->lockingLock.exit();
  255. return;
  256. }
  257. }
  258. jassert (MessageManager::instance->threadWithLock == 0);
  259. MessageManager::instance->threadWithLock = Thread::getCurrentThreadId();
  260. locked = true;
  261. needsUnlocking = true;
  262. }
  263. }
  264. }
  265. MessageManagerLock::~MessageManagerLock() throw()
  266. {
  267. if (needsUnlocking && MessageManager::instance != 0)
  268. {
  269. jassert (MessageManager::instance->currentThreadHasLockedMessageManager());
  270. ((SharedLockingEvents*) sharedEvents)->releaseEvent.signal();
  271. ((SharedLockingEvents*) sharedEvents)->decReferenceCount();
  272. MessageManager::instance->threadWithLock = 0;
  273. MessageManager::instance->lockingLock.exit();
  274. }
  275. }
  276. END_JUCE_NAMESPACE