OpenShot Library | OpenShotAudio 0.2.2
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
103 @returns true if the message was successfully posted to the message queue,
104 or false otherwise.
105 */
106 static bool callAsync (std::function<void()> functionToCall);
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 */
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 acquired 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 message 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 acquired.
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 effect 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 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager)
348};
349
350
351//==============================================================================
352/** Used to make sure that the calling thread has exclusive access to the message loop.
353
354 Because it's not thread-safe to call any of the Component or other UI classes
355 from threads other than the message thread, one of these objects can be used to
356 lock the message loop and allow this to be done. The message thread will be
357 suspended for the lifetime of the MessageManagerLock object, so create one on
358 the stack like this: @code
359 void MyThread::run()
360 {
361 someData = 1234;
362
363 const MessageManagerLock mmLock;
364 // the event loop will now be locked so it's safe to make a few calls..
365
366 myComponent->setBounds (newBounds);
367 myComponent->repaint();
368
369 // ..the event loop will now be unlocked as the MessageManagerLock goes out of scope
370 }
371 @endcode
372
373 Obviously be careful not to create one of these and leave it lying around, or
374 your app will grind to a halt!
375
376 MessageManagerLocks are re-entrant, so can be safely nested if the current thread
377 already has the lock.
378
379 Another caveat is that using this in conjunction with other CriticalSections
380 can create lots of interesting ways of producing a deadlock! In particular, if
381 your message thread calls stopThread() for a thread that uses these locks,
382 you'll get an (occasional) deadlock..
383
384 @see MessageManager, MessageManager::currentThreadHasLockedMessageManager
385
386 @tags{Events}
387*/
389{
390public:
391 //==============================================================================
392 /** Tries to acquire a lock on the message manager.
393
394 The constructor attempts to gain a lock on the message loop, and the lock will be
395 kept for the lifetime of this object.
396
397 Optionally, you can pass a thread object here, and while waiting to obtain the lock,
398 this method will keep checking whether the thread has been given the
399 Thread::signalThreadShouldExit() signal. If this happens, then it will return
400 without gaining the lock. If you pass a thread, you must check whether the lock was
401 successful by calling lockWasGained(). If this is false, your thread is being told to
402 die, so you should take evasive action.
403
404 If you pass nullptr for the thread object, it will wait indefinitely for the lock - be
405 careful when doing this, because it's very easy to deadlock if your message thread
406 attempts to call stopThread() on a thread just as that thread attempts to get the
407 message lock.
408
409 If the calling thread already has the lock, nothing will be done, so it's safe and
410 quick to use these locks recursively.
411
412 E.g.
413 @code
414 void run()
415 {
416 ...
417
418 while (! threadShouldExit())
419 {
420 MessageManagerLock mml (Thread::getCurrentThread());
421
422 if (! mml.lockWasGained())
423 return; // another thread is trying to kill us!
424
425 ..do some locked stuff here..
426 }
427
428 ..and now the MM is now unlocked..
429 }
430 @endcode
431
432 */
433 MessageManagerLock (Thread* threadToCheckForExitSignal = nullptr);
434
435 //==============================================================================
436 /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob
437 instead of a thread.
438
439 See the MessageManagerLock (Thread*) constructor for details on how this works.
440 */
441 MessageManagerLock (ThreadPoolJob* jobToCheckForExitSignal);
442
443 //==============================================================================
444 /** Releases the current thread's lock on the message manager.
445
446 Make sure this object is created and deleted by the same thread,
447 otherwise there are no guarantees what will happen!
448 */
449 ~MessageManagerLock() override;
450
451 //==============================================================================
452 /** Returns true if the lock was successfully acquired.
453 (See the constructor that takes a Thread for more info).
454 */
455 bool lockWasGained() const noexcept { return locked; }
456
457private:
458 //==============================================================================
460 bool locked;
461
462 //==============================================================================
463 bool attemptLock (Thread*, ThreadPoolJob*);
464 void exitSignalSent() override;
465
466 JUCE_DECLARE_NON_COPYABLE (MessageManagerLock)
467};
468
469//==============================================================================
470/** This macro is used to catch unsafe use of functions which expect to only be called
471 on the message thread, or when a MessageManagerLock is in place.
472 It will also fail if you try to use the function before the message manager has been
473 created, which could happen if you accidentally invoke it during a static constructor.
474*/
475#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED \
476 jassert (juce::MessageManager::existsAndIsLockedByCurrentThread());
477
478/** This macro is used to catch unsafe use of functions which expect to only be called
479 on the message thread.
480 It will also fail if you try to use the function before the message manager has been
481 created, which could happen if you accidentally invoke it during a static constructor.
482*/
483#define JUCE_ASSERT_MESSAGE_THREAD \
484 jassert (juce::MessageManager::existsAndIsCurrentThread());
485
486/** This macro is used to catch unsafe use of functions which expect to not be called
487 outside the lifetime of the MessageManager.
488*/
489#define JUCE_ASSERT_MESSAGE_MANAGER_EXISTS \
490 jassert (juce::MessageManager::getInstanceWithoutCreating() != nullptr);
491
492
493} // namespace juce
494
495/** @}*/
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.
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.
Definition: juce_Thread.h:185
Encapsulates a thread.
Definition: juce_Thread.h:47
void * ThreadID
A value type used for thread IDs.
Definition: juce_Thread.h:308
Allows threads to wait for events triggered by other threads.
#define JUCE_API
This macro is added to all JUCE public class declarations.