OpenShot Library | libopenshot-audio 0.2.0
juce_MessageManager.h
1
2/** @weakgroup juce_events-messages
3 * @{
4 */
5/*
6 ==============================================================================
7
8 This file is part of the JUCE library.
9 Copyright (c) 2017 - ROLI Ltd.
10
11 JUCE is an open source library subject to commercial or open-source
12 licensing.
13
14 The code included in this file is provided under the terms of the ISC license
15 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16 To use, copy, modify, and/or distribute this software for any purpose with or
17 without fee is hereby granted provided that the above copyright notice and
18 this permission notice appear in all copies.
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29
30class MessageManagerLock;
31class ThreadPoolJob;
32class ActionListener;
33class ActionBroadcaster;
34
35//==============================================================================
36#if JUCE_MODULE_AVAILABLE_juce_opengl
37class OpenGLContext;
38#endif
39
40//==============================================================================
41/** See MessageManager::callFunctionOnMessageThread() for use of this function type. */
42using MessageCallbackFunction = void* (void* userData);
43
44
45//==============================================================================
46/**
47 This class is in charge of the application's event-dispatch loop.
48
49 @see Message, CallbackMessage, MessageManagerLock, JUCEApplication, JUCEApplicationBase
50
51 @tags{Events}
52*/
54{
55public:
56 //==============================================================================
57 /** Returns the global instance of the MessageManager. */
58 static MessageManager* getInstance();
59
60 /** Returns the global instance of the MessageManager, or nullptr if it doesn't exist. */
61 static MessageManager* getInstanceWithoutCreating() noexcept;
62
63 /** Deletes the global MessageManager instance.
64 Does nothing if no instance had been created.
65 */
66 static void deleteInstance();
67
68 //==============================================================================
69 /** Runs the event dispatch loop until a stop message is posted.
70
71 This method is only intended to be run by the application's startup routine,
72 as it blocks, and will only return after the stopDispatchLoop() method has been used.
73
74 @see stopDispatchLoop
75 */
77
78 /** Sends a signal that the dispatch loop should terminate.
79
80 After this is called, the runDispatchLoop() or runDispatchLoopUntil() methods
81 will be interrupted and will return.
82
83 @see runDispatchLoop
84 */
86
87 /** Returns true if the stopDispatchLoop() method has been called.
88 */
89 bool hasStopMessageBeenSent() const noexcept { return quitMessagePosted.get() != 0; }
90
91 #if JUCE_MODAL_LOOPS_PERMITTED || DOXYGEN
92 /** Synchronously dispatches messages until a given time has elapsed.
93
94 Returns false if a quit message has been posted by a call to stopDispatchLoop(),
95 otherwise returns true.
96 */
97 bool runDispatchLoopUntil (int millisecondsToRunFor);
98 #endif
99
100 //==============================================================================
101 /** Asynchronously invokes a function or C++11 lambda on the message thread. */
102 template <typename FunctionType>
103 static void callAsync (FunctionType functionToCall)
104 {
105 new AsyncCallInvoker<FunctionType> (functionToCall);
106 }
107
108 /** Calls a function using the message-thread.
109
110 This can be used by any thread to cause this function to be called-back
111 by the message thread. If it's the message-thread that's calling this method,
112 then the function will just be called; if another thread is calling, a message
113 will be posted to the queue, and this method will block until that message
114 is delivered, the function is called, and the result is returned.
115
116 Be careful not to cause any deadlocks with this! It's easy to do - e.g. if the caller
117 thread has a critical section locked, which an unrelated message callback then tries to lock
118 before the message thread gets round to processing this callback.
119
120 @param callback the function to call - its signature must be @code
121 void* myCallbackFunction (void*) @endcode
122 @param userData a user-defined pointer that will be passed to the function that gets called
123 @returns the value that the callback function returns.
124 @see MessageManagerLock
125 */
126 void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData);
127
128 /** Returns true if the caller-thread is the message thread. */
129 bool isThisTheMessageThread() const noexcept;
130
131 /** Called to tell the manager that the current thread is the one that's running the dispatch loop.
132
133 (Best to ignore this method unless you really know what you're doing..)
134 @see getCurrentMessageThread
135 */
136 void setCurrentThreadAsMessageThread();
137
138 /** Returns the ID of the current message thread, as set by setCurrentThreadAsMessageThread().
139
140 (Best to ignore this method unless you really know what you're doing..)
141 @see setCurrentThreadAsMessageThread
142 */
143 Thread::ThreadID getCurrentMessageThread() const noexcept { return messageThreadId; }
144
145 /** Returns true if the caller thread has currently got the message manager locked.
146
147 see the MessageManagerLock class for more info about this.
148
149 This will be true if the caller is the message thread, because that automatically
150 gains a lock while a message is being dispatched.
151 */
152 bool currentThreadHasLockedMessageManager() const noexcept;
153
154 /** Returns true if there's an instance of the MessageManager, and if the current thread
155 has the lock on it.
156 */
157 static bool existsAndIsLockedByCurrentThread() noexcept;
158
159 /** Returns true if there's an instance of the MessageManager, and if the current thread
160 is running it.
161 */
162 static bool existsAndIsCurrentThread() noexcept;
163
164 //==============================================================================
165 /** Sends a message to all other JUCE applications that are running.
166
167 @param messageText the string that will be passed to the actionListenerCallback()
168 method of the broadcast listeners in the other app.
169 @see registerBroadcastListener, ActionListener
170 */
171 static void broadcastMessage (const String& messageText);
172
173 /** Registers a listener to get told about broadcast messages.
174
175 The actionListenerCallback() callback's string parameter
176 is the message passed into broadcastMessage().
177
178 @see broadcastMessage
179 */
180 void registerBroadcastListener (ActionListener* listener);
181
182 /** Deregisters a broadcast listener. */
183 void deregisterBroadcastListener (ActionListener* listener);
184
185 //==============================================================================
186 /** Internal class used as the base class for all message objects.
187 You shouldn't need to use this directly - see the CallbackMessage or Message
188 classes instead.
189 */
191 {
192 public:
193 MessageBase() = default;
194 ~MessageBase() override = default;
195
196 virtual void messageCallback() = 0;
197 bool post();
198
200
201 JUCE_DECLARE_NON_COPYABLE (MessageBase)
202 };
203
204 //==============================================================================
205 /** A lock you can use to lock the message manager. You can use this class with
206 the RAII-based ScopedLock classes.
207 */
208 class Lock
209 {
210 public:
211 /**
212 Creates a new critical section to exclusively access methods which can
213 only be called when the message manager is locked.
214
215 Unlike CrititcalSection, multiple instances of this lock class provide
216 exclusive access to a single resource - the MessageManager.
217 */
218 Lock();
219
220 /** Destructor. */
221 ~Lock();
222
223 /** Acquires the message manager lock.
224
225 If the caller thread already has exclusive access to the MessageManager, this method
226 will return immediately.
227 If another thread is currently using the MessageManager, this will wait until that
228 thread releases the lock to the MessageManager.
229
230 This call will only exit if the lock was accquired by this thread. Calling abort while
231 a thread is waiting for enter to finish, will have no effect.
232
233 @see exit, abort
234 */
235 void enter() const noexcept;
236
237 /** Attempts to lock the meesage manager and exits if abort is called.
238
239 This method behaves identically to enter, except that it will abort waiting for
240 the lock if the abort method is called.
241
242 Unlike other JUCE critical sections, this method **will** block waiting for the lock.
243
244 To ensure predictable behaviour, you should re-check your abort condition if tryEnter
245 returns false.
246
247 This method can be used if you want to do some work while waiting for the
248 MessageManagerLock:
249
250 void doWorkWhileWaitingForMessageManagerLock()
251 {
252 MessageManager::Lock::ScopedTryLockType mmLock (messageManagerLock);
253
254 while (! mmLock.isLocked())
255 {
256 while (workQueue.size() > 0)
257 {
258 auto work = workQueue.pop();
259 doSomeWork (work);
260 }
261
262 // this will block until we either have the lock or there is work
263 mmLock.retryLock();
264 }
265
266 // we have the mmlock
267 // do some message manager stuff like resizing and painting components
268 }
269
270 // called from another thread
271 void addWorkToDo (Work work)
272 {
273 queue.push (work);
274 messageManagerLock.abort();
275 }
276
277 @returns false if waiting for a lock was aborted, true if the lock was accquired.
278 @see enter, abort, ScopedTryLock
279 */
280 bool tryEnter() const noexcept;
281
282 /** Releases the message manager lock.
283 @see enter, ScopedLock
284 */
285 void exit() const noexcept;
286
287 /** Unblocks a thread which is waiting in tryEnter
288 Call this method if you want to unblock a thread which is waiting for the
289 MessageManager lock in tryEnter.
290 This method does not have any effetc on a thread waiting for a lock in enter.
291 @see tryEnter
292 */
293 void abort() const noexcept;
294
295 //==============================================================================
296 /** Provides the type of scoped lock to use with a CriticalSection. */
298
299 /** Provides the type of scoped unlocker to use with a CriticalSection. */
301
302 /** Provides the type of scoped try-locker to use with a CriticalSection. */
304
305 private:
306 struct BlockingMessage;
308
309 bool tryAcquire (bool) const noexcept;
310 void messageCallback() const;
311
312 //==============================================================================
313 mutable ReferenceCountedObjectPtr<BlockingMessage> blockingMessage;
314 WaitableEvent lockedEvent;
315 mutable Atomic<int> abortWait, lockGained;
316 };
317
318 //==============================================================================
319 #ifndef DOXYGEN
320 // Internal methods - do not use!
321 void deliverBroadcastMessage (const String&);
322 ~MessageManager() noexcept;
323 #endif
324
325private:
326 //==============================================================================
327 MessageManager() noexcept;
328
329 static MessageManager* instance;
330
331 friend class MessageBase;
332 class QuitMessage;
333 friend class QuitMessage;
334 friend class MessageManagerLock;
335
336 std::unique_ptr<ActionBroadcaster> broadcaster;
337 Atomic<int> quitMessagePosted { 0 }, quitMessageReceived { 0 };
338 Thread::ThreadID messageThreadId;
339 Atomic<Thread::ThreadID> threadWithLock;
340
341 static bool postMessageToSystemQueue (MessageBase*);
342 static void* exitModalLoopCallback (void*);
343 static void doPlatformSpecificInitialisation();
344 static void doPlatformSpecificShutdown();
345 static bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
346
347 template <typename FunctionType>
348 struct AsyncCallInvoker : public MessageBase
349 {
350 AsyncCallInvoker (FunctionType f) : callback (f) { post(); }
351 void messageCallback() override { callback(); }
352 FunctionType callback;
353
354 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncCallInvoker)
355 };
356
357 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager)
358};
359
360
361//==============================================================================
362/** Used to make sure that the calling thread has exclusive access to the message loop.
363
364 Because it's not thread-safe to call any of the Component or other UI classes
365 from threads other than the message thread, one of these objects can be used to
366 lock the message loop and allow this to be done. The message thread will be
367 suspended for the lifetime of the MessageManagerLock object, so create one on
368 the stack like this: @code
369 void MyThread::run()
370 {
371 someData = 1234;
372
373 const MessageManagerLock mmLock;
374 // the event loop will now be locked so it's safe to make a few calls..
375
376 myComponent->setBounds (newBounds);
377 myComponent->repaint();
378
379 // ..the event loop will now be unlocked as the MessageManagerLock goes out of scope
380 }
381 @endcode
382
383 Obviously be careful not to create one of these and leave it lying around, or
384 your app will grind to a halt!
385
386 MessageManagerLocks are re-entrant, so can be safely nested if the current thread
387 already has the lock.
388
389 Another caveat is that using this in conjunction with other CriticalSections
390 can create lots of interesting ways of producing a deadlock! In particular, if
391 your message thread calls stopThread() for a thread that uses these locks,
392 you'll get an (occasional) deadlock..
393
394 @see MessageManager, MessageManager::currentThreadHasLockedMessageManager
395
396 @tags{Events}
397*/
399{
400public:
401 //==============================================================================
402 /** Tries to acquire a lock on the message manager.
403
404 The constructor attempts to gain a lock on the message loop, and the lock will be
405 kept for the lifetime of this object.
406
407 Optionally, you can pass a thread object here, and while waiting to obtain the lock,
408 this method will keep checking whether the thread has been given the
409 Thread::signalThreadShouldExit() signal. If this happens, then it will return
410 without gaining the lock. If you pass a thread, you must check whether the lock was
411 successful by calling lockWasGained(). If this is false, your thread is being told to
412 die, so you should take evasive action.
413
414 If you pass nullptr for the thread object, it will wait indefinitely for the lock - be
415 careful when doing this, because it's very easy to deadlock if your message thread
416 attempts to call stopThread() on a thread just as that thread attempts to get the
417 message lock.
418
419 If the calling thread already has the lock, nothing will be done, so it's safe and
420 quick to use these locks recursively.
421
422 E.g.
423 @code
424 void run()
425 {
426 ...
427
428 while (! threadShouldExit())
429 {
430 MessageManagerLock mml (Thread::getCurrentThread());
431
432 if (! mml.lockWasGained())
433 return; // another thread is trying to kill us!
434
435 ..do some locked stuff here..
436 }
437
438 ..and now the MM is now unlocked..
439 }
440 @endcode
441
442 */
443 MessageManagerLock (Thread* threadToCheckForExitSignal = nullptr);
444
445 //==============================================================================
446 /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob
447 instead of a thread.
448
449 See the MessageManagerLock (Thread*) constructor for details on how this works.
450 */
451 MessageManagerLock (ThreadPoolJob* jobToCheckForExitSignal);
452
453 //==============================================================================
454 /** Releases the current thread's lock on the message manager.
455
456 Make sure this object is created and deleted by the same thread,
457 otherwise there are no guarantees what will happen!
458 */
459 ~MessageManagerLock() override;
460
461 //==============================================================================
462 /** Returns true if the lock was successfully acquired.
463 (See the constructor that takes a Thread for more info).
464 */
465 bool lockWasGained() const noexcept { return locked; }
466
467private:
468 //==============================================================================
470 bool locked;
471
472 //==============================================================================
473 bool attemptLock (Thread*, ThreadPoolJob*);
474 void exitSignalSent() override;
475
476 JUCE_DECLARE_NON_COPYABLE (MessageManagerLock)
477};
478
479//==============================================================================
480/** This macro is used to catch unsafe use of functions which expect to only be called
481 on the message thread, or when a MessageManagerLock is in place.
482 It will also fail if you try to use the function before the message manager has been
483 created, which could happen if you accidentally invoke it during a static constructor.
484*/
485#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED \
486 jassert (juce::MessageManager::existsAndIsLockedByCurrentThread());
487
488/** This macro is used to catch unsafe use of functions which expect to only be called
489 on the message thread.
490 It will also fail if you try to use the function before the message manager has been
491 created, which could happen if you accidentally invoke it during a static constructor.
492*/
493#define JUCE_ASSERT_MESSAGE_THREAD \
494 jassert (juce::MessageManager::existsAndIsCurrentThread());
495
496/** This macro is used to catch unsafe use of functions which expect to not be called
497 outside the lifetime of the MessageManager.
498*/
499#define JUCE_ASSERT_MESSAGE_MANAGER_EXISTS \
500 jassert (juce::MessageManager::getInstanceWithoutCreating() != nullptr);
501
502
503} // namespace juce
504
505/** @}*/
Manages a list of ActionListeners, and can send them messages.
Interface class for delivery of events that are sent by an ActionBroadcaster.
Automatically locks and unlocks a mutex object.
Automatically locks and unlocks a mutex object.
Automatically unlocks and re-locks a mutex object.
Used to make sure that the calling thread has exclusive access to the message loop.
bool lockWasGained() const noexcept
Returns true if the lock was successfully acquired.
A lock you can use to lock the message manager.
Internal class used as the base class for all message objects.
This class is in charge of the application's event-dispatch loop.
bool runDispatchLoopUntil(int millisecondsToRunFor)
Synchronously dispatches messages until a given time has elapsed.
void runDispatchLoop()
Runs the event dispatch loop until a stop message is posted.
bool hasStopMessageBeenSent() const noexcept
Returns true if the stopDispatchLoop() method has been called.
void stopDispatchLoop()
Sends a signal that the dispatch loop should terminate.
static void callAsync(FunctionType functionToCall)
Asynchronously invokes a function or C++11 lambda on the message thread.
A smart-pointer class which points to a reference-counted object.
A base class which provides methods for reference-counting.
The JUCE String class!
Definition juce_String.h:43
A task that is executed by a ThreadPool object.
Used to receive callbacks for thread exit calls.
Encapsulates a thread.
Definition juce_Thread.h:47
Allows threads to wait for events triggered by other threads.
#define JUCE_API
This macro is added to all JUCE public class declarations.
A simple wrapper around std::atomic.
Definition juce_Atomic.h:46