1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: declares wxEventLoop class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 #ifndef _WX_EVTLOOP_H_
13 #define _WX_EVTLOOP_H_
19 NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
20 ------------------------------------------
22 The YieldFor() function helps to avoid re-entrancy problems and problems
23 caused by out-of-order event processing
24 (see "wxYield-like problems" and "wxProgressDialog+threading BUG" wx-dev threads).
26 The logic behind YieldFor() is simple: it analyzes the queue of the native
27 events generated by the underlying GUI toolkit and picks out and processes
28 only those matching the given mask.
30 It's important to note that YieldFor() is used to selectively process the
31 events generated by the NATIVE toolkit.
32 Events syntethized by wxWidgets code or by user code are instead selectively
33 processed thanks to the logic built into wxEvtHandler::ProcessPendingEvents().
34 In fact, when wxEvtHandler::ProcessPendingEvents gets called from inside a
35 YieldFor() call, wxEventLoopBase::IsEventAllowedInsideYield is used to decide
36 if the pending events for that event handler can be processed.
37 If all the pending events associated with that event handler result as "not processable",
38 the event handler "delays" itself calling wxEventLoopBase::DelayPendingEventHandler
39 (so it's moved: m_handlersWithPendingEvents => m_handlersWithPendingDelayedEvents).
40 Last, wxEventLoopBase::ProcessPendingEvents() before exiting moves the delayed
41 event handlers back into the list of handlers with pending events
42 (m_handlersWithPendingDelayedEvents => m_handlersWithPendingEvents) so that
43 a later call to ProcessPendingEvents() (possibly outside the YieldFor() call)
44 will process all pending events as usual.
47 // ----------------------------------------------------------------------------
48 // wxEventLoopBase: interface for wxEventLoop
49 // ----------------------------------------------------------------------------
51 class WXDLLIMPEXP_BASE wxEventLoopBase
54 // trivial, but needed (because of wxEventLoopBase) ctor
58 virtual ~wxEventLoopBase() { }
60 // use this to check whether the event loop was successfully created before
62 virtual bool IsOk() const { return true; }
64 // returns true if this is the main loop
68 // dispatch&processing
69 // -------------------
71 // start the event loop, return the exit code when it is finished
72 virtual int Run() = 0;
74 // is this event loop running now?
76 // notice that even if this event loop hasn't terminated yet but has just
77 // spawned a nested (e.g. modal) event loop, this would return false
78 bool IsRunning() const;
80 // exit from the loop with the given exit code
81 virtual void Exit(int rc
= 0) = 0;
83 // return true if any events are available
84 virtual bool Pending() const = 0;
86 // dispatch a single event, return false if we should exit from the loop
87 virtual bool Dispatch() = 0;
89 // same as Dispatch() but doesn't wait for longer than the specified (in
90 // ms) timeout, return true if an event was processed, false if we should
91 // exit the loop or -1 if timeout expired
92 virtual int DispatchTimeout(unsigned long timeout
) = 0;
94 // implement this to wake up the loop: usually done by posting a dummy event
95 // to it (can be called from non main thread)
96 virtual void WakeUp() = 0;
102 // process all events in the wxHandlersWithPendingEvents list -- it is necessary
103 // to call this function to process posted events. This happens during each
104 // event loop iteration in GUI mode but if there is no main loop, it may be
105 // also called directly.
106 virtual void ProcessPendingEvents();
108 // check if there are pending events on global pending event list
109 bool HasPendingEvents() const;
111 // temporary suspends processing of the pending events
112 void SuspendProcessingOfPendingEvents();
114 // resume processing of the pending events previously stopped because of a
115 // call to SuspendProcessingOfPendingEvents()
116 void ResumeProcessingOfPendingEvents();
118 // called by ~wxEvtHandler to (eventually) remove the handler from the list of
119 // the handlers with pending events
120 void RemovePendingEventHandler(wxEvtHandler
* toRemove
);
122 // adds an event handler to the list of the handlers with pending events
123 void AppendPendingEventHandler(wxEvtHandler
* toAppend
);
125 // moves the event handler from the list of the handlers with pending events
126 //to the list of the handlers with _delayed_ pending events
127 void DelayPendingEventHandler(wxEvtHandler
* toDelay
);
133 // make sure that idle events are sent again
134 virtual void WakeUpIdle();
136 // this virtual function is called when the application
137 // becomes idle and normally just sends wxIdleEvent to all interested
140 // it should return true if more idle events are needed, false if not
141 virtual bool ProcessIdle();
144 // Yield-related hooks
145 // -------------------
147 // process all currently pending events right now
149 // it is an error to call Yield() recursively unless the value of
150 // onlyIfNeeded is true
152 // WARNING: this function is dangerous as it can lead to unexpected
153 // reentrancies (i.e. when called from an event handler it
154 // may result in calling the same event handler again), use
155 // with _extreme_ care or, better, don't use at all!
156 bool Yield(bool onlyIfNeeded
= false);
157 virtual bool YieldFor(long eventsToProcess
) = 0;
159 // returns true if the main thread is inside a Yield() call
160 virtual bool IsYielding() const
161 { return m_isInsideYield
; }
163 // returns true if events of the given event category should be immediately
164 // processed inside a wxApp::Yield() call or rather should be queued for
165 // later processing by the main event loop
166 virtual bool IsEventAllowedInsideYield(wxEventCategory cat
) const
167 { return (m_eventsToProcessInsideYield
& cat
) != 0; }
169 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
175 // return currently active (running) event loop, may be NULL
176 static wxEventLoopBase
*GetActive() { return ms_activeLoop
; }
178 // set currently active (running) event loop
179 static void SetActive(wxEventLoopBase
* loop
);
183 // this function should be called before the event loop terminates, whether
184 // this happens normally (because of Exit() call) or abnormally (because of
185 // an exception thrown from inside the loop)
186 virtual void OnExit();
188 // the pointer to currently active loop
189 static wxEventLoopBase
*ms_activeLoop
;
191 // the array of the handlers with pending events which needs to be processed
192 // inside ProcessPendingEvents()
193 wxEvtHandlerArray m_handlersWithPendingEvents
;
195 // helper array used by ProcessPendingEvents()
196 wxEvtHandlerArray m_handlersWithPendingDelayedEvents
;
199 // this critical section protects both the lists above
200 wxCriticalSection m_handlersWithPendingEventsLocker
;
204 bool m_isInsideYield
;
205 long m_eventsToProcessInsideYield
;
207 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase
);
210 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || defined(__UNIX__)
212 // this class can be used to implement a standard event loop logic using
213 // Pending() and Dispatch()
215 // it also handles idle processing automatically
216 class WXDLLIMPEXP_BASE wxEventLoopManual
: public wxEventLoopBase
221 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
222 // terminating when Exit() is called
225 // sets the "should exit" flag and wakes up the loop so that it terminates
227 virtual void Exit(int rc
= 0);
230 // may be overridden to perform some action at the start of each new event
232 virtual void OnNextIteration() { }
235 // the loop exit code
238 // should we exit the loop?
242 #endif // platforms using "manual" loop
244 // we're moving away from old m_impl wxEventLoop model as otherwise the user
245 // code doesn't have access to platform-specific wxEventLoop methods and this
246 // can sometimes be very useful (e.g. under MSW this is necessary for
247 // integration with MFC) but currently this is done for MSW only, other ports
248 // should follow a.s.a.p.
249 #if defined(__WXPALMOS__)
250 #include "wx/palmos/evtloop.h"
251 #elif defined(__WXMSW__)
252 #include "wx/msw/evtloop.h"
253 #elif defined(__WXMAC__)
254 #include "wx/osx/evtloop.h"
255 #elif defined(__WXCOCOA__)
256 #include "wx/cocoa/evtloop.h"
257 #elif defined(__WXDFB__)
258 #include "wx/dfb/evtloop.h"
259 #elif defined(__WXGTK20__)
260 #include "wx/gtk/evtloop.h"
261 #else // other platform
263 #include "wx/stopwatch.h" // for wxMilliClock_t
265 class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl
;
267 class WXDLLIMPEXP_CORE wxGUIEventLoop
: public wxEventLoopBase
270 wxGUIEventLoop() { m_impl
= NULL
; }
271 virtual ~wxGUIEventLoop();
274 virtual void Exit(int rc
= 0);
275 virtual bool Pending() const;
276 virtual bool Dispatch();
277 virtual int DispatchTimeout(unsigned long timeout
)
279 // TODO: this is, of course, horribly inefficient and a proper wait with
280 // timeout should be implemented for all ports natively...
281 const wxMilliClock_t timeEnd
= wxGetLocalTimeMillis() + timeout
;
287 if ( wxGetLocalTimeMillis() >= timeEnd
)
291 virtual void WakeUp() { }
292 virtual bool YieldFor(long eventsToProcess
);
295 // the pointer to the port specific implementation class
296 wxEventLoopImpl
*m_impl
;
298 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop
);
303 // also include the header defining wxConsoleEventLoop for Unix systems
304 #if defined(__UNIX__)
305 #include "wx/unix/evtloop.h"
308 // we use a class rather than a typedef because wxEventLoop is forward-declared
311 class wxEventLoop
: public wxGUIEventLoop
{ };
313 // we can't define wxEventLoop differently in GUI and base libraries so use
314 // a #define to still allow writing wxEventLoop in the user code
315 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WXMSW__) || defined(__UNIX__))
316 #define wxEventLoop wxConsoleEventLoop
317 #else // we still must define it somehow for the code below...
318 #define wxEventLoop wxEventLoopBase
322 inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
325 // ----------------------------------------------------------------------------
327 // ----------------------------------------------------------------------------
329 // this is a naive generic implementation which uses wxWindowDisabler to
330 // implement modality, we will surely need platform-specific implementations
331 // too, this generic implementation is here only temporarily to see how it
333 class WXDLLIMPEXP_CORE wxModalEventLoop
: public wxGUIEventLoop
336 wxModalEventLoop(wxWindow
*winModal
)
338 m_windowDisabler
= new wxWindowDisabler(winModal
);
342 virtual void OnExit()
344 delete m_windowDisabler
;
345 m_windowDisabler
= NULL
;
347 wxGUIEventLoop::OnExit();
351 wxWindowDisabler
*m_windowDisabler
;
356 // ----------------------------------------------------------------------------
357 // wxEventLoopActivator: helper class for wxEventLoop implementations
358 // ----------------------------------------------------------------------------
360 // this object sets the wxEventLoop given to the ctor as the currently active
361 // one and unsets it in its dtor, this is especially useful in presence of
362 // exceptions but is more tidy even when we don't use them
363 class wxEventLoopActivator
366 wxEventLoopActivator(wxEventLoopBase
*evtLoop
)
368 m_evtLoopOld
= wxEventLoopBase::GetActive();
369 wxEventLoopBase::SetActive(evtLoop
);
372 ~wxEventLoopActivator()
374 // restore the previously active event loop
375 wxEventLoopBase::SetActive(m_evtLoopOld
);
379 wxEventLoopBase
*m_evtLoopOld
;
382 #if wxUSE_CONSOLE_EVENTLOOP
384 class wxEventLoopGuarantor
387 wxEventLoopGuarantor()
390 if (!wxEventLoop::GetActive())
392 m_evtLoopNew
= new wxEventLoop
;
393 wxEventLoop::SetActive(m_evtLoopNew
);
397 ~wxEventLoopGuarantor()
401 wxEventLoop::SetActive(NULL
);
407 wxEventLoop
*m_evtLoopNew
;
410 #endif // wxUSE_CONSOLE_EVENTLOOP
412 #endif // _WX_EVTLOOP_H_