Audio plugin host https://kx.studio/carla
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.

juce_MessageManager.h 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software 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. #ifndef JUCE_MESSAGEMANAGER_H_INCLUDED
  18. #define JUCE_MESSAGEMANAGER_H_INCLUDED
  19. class MessageManagerLock;
  20. class ThreadPoolJob;
  21. class ActionListener;
  22. class ActionBroadcaster;
  23. //==============================================================================
  24. /** See MessageManager::callFunctionOnMessageThread() for use of this function type
  25. */
  26. typedef void* (MessageCallbackFunction) (void* userData);
  27. //==============================================================================
  28. /**
  29. This class is in charge of the application's event-dispatch loop.
  30. @see Message, CallbackMessage, MessageManagerLock, JUCEApplication, JUCEApplicationBase
  31. */
  32. class JUCE_API MessageManager
  33. {
  34. public:
  35. //==============================================================================
  36. /** Returns the global instance of the MessageManager. */
  37. static MessageManager* getInstance();
  38. /** Returns the global instance of the MessageManager, or nullptr if it doesn't exist. */
  39. static MessageManager* getInstanceWithoutCreating() noexcept;
  40. /** Deletes the global MessageManager instance.
  41. Does nothing if no instance had been created.
  42. */
  43. static void deleteInstance();
  44. //==============================================================================
  45. /** Runs the event dispatch loop until a stop message is posted.
  46. This method is only intended to be run by the application's startup routine,
  47. as it blocks, and will only return after the stopDispatchLoop() method has been used.
  48. @see stopDispatchLoop
  49. */
  50. void runDispatchLoop();
  51. /** Sends a signal that the dispatch loop should terminate.
  52. After this is called, the runDispatchLoop() or runDispatchLoopUntil() methods
  53. will be interrupted and will return.
  54. @see runDispatchLoop
  55. */
  56. void stopDispatchLoop();
  57. /** Returns true if the stopDispatchLoop() method has been called.
  58. */
  59. bool hasStopMessageBeenSent() const noexcept { return quitMessagePosted; }
  60. #if JUCE_MODAL_LOOPS_PERMITTED || DOXYGEN
  61. /** Synchronously dispatches messages until a given time has elapsed.
  62. Returns false if a quit message has been posted by a call to stopDispatchLoop(),
  63. otherwise returns true.
  64. */
  65. bool runDispatchLoopUntil (int millisecondsToRunFor);
  66. #endif
  67. //==============================================================================
  68. /** Calls a function using the message-thread.
  69. This can be used by any thread to cause this function to be called-back
  70. by the message thread. If it's the message-thread that's calling this method,
  71. then the function will just be called; if another thread is calling, a message
  72. will be posted to the queue, and this method will block until that message
  73. is delivered, the function is called, and the result is returned.
  74. Be careful not to cause any deadlocks with this! It's easy to do - e.g. if the caller
  75. thread has a critical section locked, which an unrelated message callback then tries to lock
  76. before the message thread gets round to processing this callback.
  77. @param callback the function to call - its signature must be @code
  78. void* myCallbackFunction (void*) @endcode
  79. @param userData a user-defined pointer that will be passed to the function that gets called
  80. @returns the value that the callback function returns.
  81. @see MessageManagerLock
  82. */
  83. void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData);
  84. /** Returns true if the caller-thread is the message thread. */
  85. bool isThisTheMessageThread() const noexcept;
  86. /** Called to tell the manager that the current thread is the one that's running the dispatch loop.
  87. (Best to ignore this method unless you really know what you're doing..)
  88. @see getCurrentMessageThread
  89. */
  90. void setCurrentThreadAsMessageThread();
  91. /** Returns the ID of the current message thread, as set by setCurrentThreadAsMessageThread().
  92. (Best to ignore this method unless you really know what you're doing..)
  93. @see setCurrentThreadAsMessageThread
  94. */
  95. Thread::ThreadID getCurrentMessageThread() const noexcept { return messageThreadId; }
  96. /** Returns true if the caller thread has currenltly got the message manager locked.
  97. see the MessageManagerLock class for more info about this.
  98. This will be true if the caller is the message thread, because that automatically
  99. gains a lock while a message is being dispatched.
  100. */
  101. bool currentThreadHasLockedMessageManager() const noexcept;
  102. //==============================================================================
  103. /** Sends a message to all other JUCE applications that are running.
  104. @param messageText the string that will be passed to the actionListenerCallback()
  105. method of the broadcast listeners in the other app.
  106. @see registerBroadcastListener, ActionListener
  107. */
  108. static void broadcastMessage (const String& messageText);
  109. /** Registers a listener to get told about broadcast messages.
  110. The actionListenerCallback() callback's string parameter
  111. is the message passed into broadcastMessage().
  112. @see broadcastMessage
  113. */
  114. void registerBroadcastListener (ActionListener* listener);
  115. /** Deregisters a broadcast listener. */
  116. void deregisterBroadcastListener (ActionListener* listener);
  117. //==============================================================================
  118. /** Internal class used as the base class for all message objects.
  119. You shouldn't need to use this directly - see the CallbackMessage or Message
  120. classes instead.
  121. */
  122. class JUCE_API MessageBase : public ReferenceCountedObject
  123. {
  124. public:
  125. MessageBase() noexcept {}
  126. virtual ~MessageBase() {}
  127. virtual void messageCallback() = 0;
  128. void post();
  129. typedef ReferenceCountedObjectPtr<MessageBase> Ptr;
  130. JUCE_DECLARE_NON_COPYABLE (MessageBase)
  131. };
  132. //==============================================================================
  133. #ifndef DOXYGEN
  134. // Internal methods - do not use!
  135. void deliverBroadcastMessage (const String&);
  136. ~MessageManager() noexcept;
  137. #endif
  138. private:
  139. //==============================================================================
  140. MessageManager() noexcept;
  141. static MessageManager* instance;
  142. friend class MessageBase;
  143. class QuitMessage;
  144. friend class QuitMessage;
  145. friend class MessageManagerLock;
  146. ScopedPointer <ActionBroadcaster> broadcaster;
  147. bool quitMessagePosted, quitMessageReceived;
  148. Thread::ThreadID messageThreadId;
  149. Thread::ThreadID volatile threadWithLock;
  150. CriticalSection lockingLock;
  151. static bool postMessageToSystemQueue (MessageBase*);
  152. static void* exitModalLoopCallback (void*);
  153. static void doPlatformSpecificInitialisation();
  154. static void doPlatformSpecificShutdown();
  155. static bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
  156. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager)
  157. };
  158. //==============================================================================
  159. /** Used to make sure that the calling thread has exclusive access to the message loop.
  160. Because it's not thread-safe to call any of the Component or other UI classes
  161. from threads other than the message thread, one of these objects can be used to
  162. lock the message loop and allow this to be done. The message thread will be
  163. suspended for the lifetime of the MessageManagerLock object, so create one on
  164. the stack like this: @code
  165. void MyThread::run()
  166. {
  167. someData = 1234;
  168. const MessageManagerLock mmLock;
  169. // the event loop will now be locked so it's safe to make a few calls..
  170. myComponent->setBounds (newBounds);
  171. myComponent->repaint();
  172. // ..the event loop will now be unlocked as the MessageManagerLock goes out of scope
  173. }
  174. @endcode
  175. Obviously be careful not to create one of these and leave it lying around, or
  176. your app will grind to a halt!
  177. Another caveat is that using this in conjunction with other CriticalSections
  178. can create lots of interesting ways of producing a deadlock! In particular, if
  179. your message thread calls stopThread() for a thread that uses these locks,
  180. you'll get an (occasional) deadlock..
  181. @see MessageManager, MessageManager::currentThreadHasLockedMessageManager
  182. */
  183. class JUCE_API MessageManagerLock
  184. {
  185. public:
  186. //==============================================================================
  187. /** Tries to acquire a lock on the message manager.
  188. The constructor attempts to gain a lock on the message loop, and the lock will be
  189. kept for the lifetime of this object.
  190. Optionally, you can pass a thread object here, and while waiting to obtain the lock,
  191. this method will keep checking whether the thread has been given the
  192. Thread::signalThreadShouldExit() signal. If this happens, then it will return
  193. without gaining the lock. If you pass a thread, you must check whether the lock was
  194. successful by calling lockWasGained(). If this is false, your thread is being told to
  195. die, so you should take evasive action.
  196. If you pass nullptr for the thread object, it will wait indefinitely for the lock - be
  197. careful when doing this, because it's very easy to deadlock if your message thread
  198. attempts to call stopThread() on a thread just as that thread attempts to get the
  199. message lock.
  200. If the calling thread already has the lock, nothing will be done, so it's safe and
  201. quick to use these locks recursively.
  202. E.g.
  203. @code
  204. void run()
  205. {
  206. ...
  207. while (! threadShouldExit())
  208. {
  209. MessageManagerLock mml (Thread::getCurrentThread());
  210. if (! mml.lockWasGained())
  211. return; // another thread is trying to kill us!
  212. ..do some locked stuff here..
  213. }
  214. ..and now the MM is now unlocked..
  215. }
  216. @endcode
  217. */
  218. MessageManagerLock (Thread* threadToCheckForExitSignal = nullptr);
  219. //==============================================================================
  220. /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob
  221. instead of a thread.
  222. See the MessageManagerLock (Thread*) constructor for details on how this works.
  223. */
  224. MessageManagerLock (ThreadPoolJob* jobToCheckForExitSignal);
  225. //==============================================================================
  226. /** Releases the current thread's lock on the message manager.
  227. Make sure this object is created and deleted by the same thread,
  228. otherwise there are no guarantees what will happen!
  229. */
  230. ~MessageManagerLock() noexcept;
  231. //==============================================================================
  232. /** Returns true if the lock was successfully acquired.
  233. (See the constructor that takes a Thread for more info).
  234. */
  235. bool lockWasGained() const noexcept { return locked; }
  236. private:
  237. class BlockingMessage;
  238. friend class ReferenceCountedObjectPtr<BlockingMessage>;
  239. ReferenceCountedObjectPtr<BlockingMessage> blockingMessage;
  240. bool locked;
  241. bool attemptLock (Thread*, ThreadPoolJob*);
  242. JUCE_DECLARE_NON_COPYABLE (MessageManagerLock)
  243. };
  244. #endif // JUCE_MESSAGEMANAGER_H_INCLUDED