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_
18 // TODO: implement wxEventLoopSource for MSW (it should wrap a HANDLE and be
19 // monitored using MsgWaitForMultipleObjects())
20 #if defined(__WXOSX__) || defined(__WXGTK20__) || defined(__WXDFB__) || \
21 (!wxUSE_GUI && defined(__UNIX__))
22 #define wxUSE_EVENTLOOP_SOURCE 1
24 #define wxUSE_EVENTLOOP_SOURCE 0
27 #if wxUSE_EVENTLOOP_SOURCE
28 class wxEventLoopSource
;
29 class wxEventLoopSourceHandler
;
33 NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
34 ------------------------------------------
36 The YieldFor() function helps to avoid re-entrancy problems and problems
37 caused by out-of-order event processing
38 (see "wxYield-like problems" and "wxProgressDialog+threading BUG" wx-dev threads).
40 The logic behind YieldFor() is simple: it analyzes the queue of the native
41 events generated by the underlying GUI toolkit and picks out and processes
42 only those matching the given mask.
44 It's important to note that YieldFor() is used to selectively process the
45 events generated by the NATIVE toolkit.
46 Events syntethized by wxWidgets code or by user code are instead selectively
47 processed thanks to the logic built into wxEvtHandler::ProcessPendingEvents().
48 In fact, when wxEvtHandler::ProcessPendingEvents gets called from inside a
49 YieldFor() call, wxEventLoopBase::IsEventAllowedInsideYield is used to decide
50 if the pending events for that event handler can be processed.
51 If all the pending events associated with that event handler result as "not processable",
52 the event handler "delays" itself calling wxEventLoopBase::DelayPendingEventHandler
53 (so it's moved: m_handlersWithPendingEvents => m_handlersWithPendingDelayedEvents).
54 Last, wxEventLoopBase::ProcessPendingEvents() before exiting moves the delayed
55 event handlers back into the list of handlers with pending events
56 (m_handlersWithPendingDelayedEvents => m_handlersWithPendingEvents) so that
57 a later call to ProcessPendingEvents() (possibly outside the YieldFor() call)
58 will process all pending events as usual.
61 // ----------------------------------------------------------------------------
62 // wxEventLoopBase: interface for wxEventLoop
63 // ----------------------------------------------------------------------------
65 class WXDLLIMPEXP_BASE wxEventLoopBase
68 // trivial, but needed (because of wxEventLoopBase) ctor
72 virtual ~wxEventLoopBase() { }
74 // use this to check whether the event loop was successfully created before
76 virtual bool IsOk() const { return true; }
78 // returns true if this is the main loop
81 #if wxUSE_EVENTLOOP_SOURCE
82 // create a new event loop source wrapping the given file descriptor and
83 // start monitoring it
84 virtual wxEventLoopSource
*
85 AddSourceForFD(int fd
, wxEventLoopSourceHandler
*handler
, int flags
) = 0;
86 #endif // wxUSE_EVENTLOOP_SOURCE
88 // dispatch&processing
89 // -------------------
91 // start the event loop, return the exit code when it is finished
92 virtual int Run() = 0;
94 // is this event loop running now?
96 // notice that even if this event loop hasn't terminated yet but has just
97 // spawned a nested (e.g. modal) event loop, this would return false
98 bool IsRunning() const;
100 // exit from the loop with the given exit code
101 virtual void Exit(int rc
= 0) = 0;
103 // return true if any events are available
104 virtual bool Pending() const = 0;
106 // dispatch a single event, return false if we should exit from the loop
107 virtual bool Dispatch() = 0;
109 // same as Dispatch() but doesn't wait for longer than the specified (in
110 // ms) timeout, return true if an event was processed, false if we should
111 // exit the loop or -1 if timeout expired
112 virtual int DispatchTimeout(unsigned long timeout
) = 0;
114 // implement this to wake up the loop: usually done by posting a dummy event
115 // to it (can be called from non main thread)
116 virtual void WakeUp() = 0;
122 // make sure that idle events are sent again
123 virtual void WakeUpIdle();
125 // this virtual function is called when the application
126 // becomes idle and by default it forwards to wxApp::ProcessIdle() and
127 // while it can be overridden in a custom event loop, you must call the
128 // base class version to ensure that idle events are still generated
130 // it should return true if more idle events are needed, false if not
131 virtual bool ProcessIdle();
134 // Yield-related hooks
135 // -------------------
137 // process all currently pending events right now
139 // it is an error to call Yield() recursively unless the value of
140 // onlyIfNeeded is true
142 // WARNING: this function is dangerous as it can lead to unexpected
143 // reentrancies (i.e. when called from an event handler it
144 // may result in calling the same event handler again), use
145 // with _extreme_ care or, better, don't use at all!
146 bool Yield(bool onlyIfNeeded
= false);
147 virtual bool YieldFor(long eventsToProcess
) = 0;
149 // returns true if the main thread is inside a Yield() call
150 virtual bool IsYielding() const
151 { return m_isInsideYield
; }
153 // returns true if events of the given event category should be immediately
154 // processed inside a wxApp::Yield() call or rather should be queued for
155 // later processing by the main event loop
156 virtual bool IsEventAllowedInsideYield(wxEventCategory cat
) const
157 { return (m_eventsToProcessInsideYield
& cat
) != 0; }
159 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
165 // return currently active (running) event loop, may be NULL
166 static wxEventLoopBase
*GetActive() { return ms_activeLoop
; }
168 // set currently active (running) event loop
169 static void SetActive(wxEventLoopBase
* loop
);
173 // this function should be called before the event loop terminates, whether
174 // this happens normally (because of Exit() call) or abnormally (because of
175 // an exception thrown from inside the loop)
176 virtual void OnExit();
178 // the pointer to currently active loop
179 static wxEventLoopBase
*ms_activeLoop
;
181 // YieldFor() helpers:
182 bool m_isInsideYield
;
183 long m_eventsToProcessInsideYield
;
185 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase
);
188 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || defined(__UNIX__)
190 // this class can be used to implement a standard event loop logic using
191 // Pending() and Dispatch()
193 // it also handles idle processing automatically
194 class WXDLLIMPEXP_BASE wxEventLoopManual
: public wxEventLoopBase
199 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
200 // terminating when Exit() is called
203 // sets the "should exit" flag and wakes up the loop so that it terminates
205 virtual void Exit(int rc
= 0);
208 // may be overridden to perform some action at the start of each new event
210 virtual void OnNextIteration() { }
213 // the loop exit code
216 // should we exit the loop?
220 // process all already pending events and dispatch a new one (blocking
221 // until it appears in the event queue if necessary)
223 // returns the return value of Dispatch()
224 bool ProcessEvents();
226 wxDECLARE_NO_COPY_CLASS(wxEventLoopManual
);
229 #endif // platforms using "manual" loop
231 // include the header defining wxConsoleEventLoop for Unix systems
232 #if defined(__UNIX__)
233 #include "wx/unix/evtloop.h"
236 // we're moving away from old m_impl wxEventLoop model as otherwise the user
237 // code doesn't have access to platform-specific wxEventLoop methods and this
238 // can sometimes be very useful (e.g. under MSW this is necessary for
239 // integration with MFC) but currently this is not done for all ports yet (e.g.
240 // wxX11) so fall back to the old wxGUIEventLoop definition below for them
242 #if defined(__WXPALMOS__)
243 #include "wx/palmos/evtloop.h"
244 #elif defined(__WXMSW__)
245 // this header defines both console and GUI loops for MSW
246 #include "wx/msw/evtloop.h"
247 #elif defined(__WXOSX__)
248 // CoreFoundation-based event loop is currently in wxBase so include it in
249 // any case too (although maybe it actually shouldn't be there at all)
250 #include "wx/osx/evtloop.h"
253 // include the appropriate header defining wxGUIEventLoop
255 #if 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
);
306 // we use a class rather than a typedef because wxEventLoop is
307 // forward-declared in many places
308 class wxEventLoop
: public wxGUIEventLoop
{ };
310 // we can't define wxEventLoop differently in GUI and base libraries so use
311 // a #define to still allow writing wxEventLoop in the user code
312 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WXMSW__) || defined(__UNIX__))
313 #define wxEventLoop wxConsoleEventLoop
314 #else // we still must define it somehow for the code below...
315 #define wxEventLoop wxEventLoopBase
319 inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
322 // ----------------------------------------------------------------------------
324 // ----------------------------------------------------------------------------
326 // this is a naive generic implementation which uses wxWindowDisabler to
327 // implement modality, we will surely need platform-specific implementations
328 // too, this generic implementation is here only temporarily to see how it
330 class WXDLLIMPEXP_CORE wxModalEventLoop
: public wxGUIEventLoop
333 wxModalEventLoop(wxWindow
*winModal
)
335 m_windowDisabler
= new wxWindowDisabler(winModal
);
339 virtual void OnExit()
341 delete m_windowDisabler
;
342 m_windowDisabler
= NULL
;
344 wxGUIEventLoop::OnExit();
348 wxWindowDisabler
*m_windowDisabler
;
353 // ----------------------------------------------------------------------------
354 // wxEventLoopActivator: helper class for wxEventLoop implementations
355 // ----------------------------------------------------------------------------
357 // this object sets the wxEventLoop given to the ctor as the currently active
358 // one and unsets it in its dtor, this is especially useful in presence of
359 // exceptions but is more tidy even when we don't use them
360 class wxEventLoopActivator
363 wxEventLoopActivator(wxEventLoopBase
*evtLoop
)
365 m_evtLoopOld
= wxEventLoopBase::GetActive();
366 wxEventLoopBase::SetActive(evtLoop
);
369 ~wxEventLoopActivator()
371 // restore the previously active event loop
372 wxEventLoopBase::SetActive(m_evtLoopOld
);
376 wxEventLoopBase
*m_evtLoopOld
;
379 #if wxUSE_CONSOLE_EVENTLOOP
381 class wxEventLoopGuarantor
384 wxEventLoopGuarantor()
387 if (!wxEventLoop::GetActive())
389 m_evtLoopNew
= new wxEventLoop
;
390 wxEventLoop::SetActive(m_evtLoopNew
);
394 ~wxEventLoopGuarantor()
398 wxEventLoop::SetActive(NULL
);
404 wxEventLoop
*m_evtLoopNew
;
407 #endif // wxUSE_CONSOLE_EVENTLOOP
409 #endif // _WX_EVTLOOP_H_