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_
17 #include "wx/hashset.h"
19 // ----------------------------------------------------------------------------
20 // wxEventLoopSource: source of i/o for wxEventLoop
21 // ----------------------------------------------------------------------------
23 #define wxTRACE_EVT_SOURCE "EventSource"
25 #if defined(__UNIX__) && (wxUSE_CONSOLE_EVENTLOOP || defined(__WXGTK__) || \
26 defined(__WXOSX_COCOA__))
27 #define wxUSE_EVENTLOOP_SOURCE 1
29 #define wxUSE_EVENTLOOP_SOURCE 0
32 #if wxUSE_EVENTLOOP_SOURCE
34 // handler used to process events on event loop sources
35 class WXDLLIMPEXP_BASE wxEventLoopSourceHandler
38 // called when descriptor is available for non-blocking read
39 virtual void OnReadWaiting() = 0;
41 // called when descriptor is available for non-blocking write
42 virtual void OnWriteWaiting() = 0;
44 // called when there is exception on descriptor
45 virtual void OnExceptionWaiting() = 0;
47 // virtual dtor for the base class
48 virtual ~wxEventLoopSourceHandler() { }
51 // those flags describes what events should be reported
54 wxEVENT_SOURCE_INPUT
= 0x01,
55 wxEVENT_SOURCE_OUTPUT
= 0x02,
56 wxEVENT_SOURCE_EXCEPTION
= 0x04,
57 wxEVENT_SOURCE_ALL
= wxEVENT_SOURCE_INPUT
| wxEVENT_SOURCE_OUTPUT
|
58 wxEVENT_SOURCE_EXCEPTION
,
61 class wxAbstractEventLoopSource
64 wxAbstractEventLoopSource() :
65 m_handler(NULL
), m_flags(-1)
68 wxAbstractEventLoopSource(wxEventLoopSourceHandler
* handler
, int flags
) :
69 m_handler(handler
), m_flags(flags
)
72 virtual ~wxAbstractEventLoopSource() { }
74 virtual bool IsOk() const = 0;
76 virtual void Invalidate() = 0;
78 void SetHandler(wxEventLoopSourceHandler
* handler
)
83 wxEventLoopSourceHandler
* GetHandler() const
88 void SetFlags(int flags
)
99 wxEventLoopSourceHandler
* m_handler
;
103 // This class is a simple wrapper for OS specific resources than can be a
104 // source of I/O. On Unix,for instance these are file descriptors.
106 // Instances of this class doesn't take resposibility of any resource you pass
107 // to them, I.E. you have to release them yourself.
109 class WXDLLIMPEXP_BASE wxEventLoopSourceBase
: public wxAbstractEventLoopSource
115 wxEventLoopSourceBase(const wxEventLoopSourceBase
& source
) :
116 wxAbstractEventLoopSource(source
.GetHandler(), source
.GetFlags()),
117 m_res(source
.GetResource())
121 virtual const T
InvalidResource() const
126 virtual void Invalidate()
128 SetResource(InvalidResource());
132 // sets internal value to res
133 void SetResource(T res
)
138 // returns associated resource
139 T
GetResource() const
144 virtual bool IsOk() const
146 // flags < 0 are invalid and flags == 0 mean monitoring for nothing
147 return m_res
!= InvalidResource() && m_handler
&& m_flags
>=1;
151 // empty ctor, beacuse we often store event sources as values
152 wxEventLoopSourceBase() :
153 wxAbstractEventLoopSource(),
154 m_res(InvalidResource())
158 // ctor setting internal value to the os resource res
159 wxEventLoopSourceBase(T res
, wxEventLoopSourceHandler
* handler
,
161 wxAbstractEventLoopSource(handler
, flags
),
168 #if defined(__WXMAC__)
169 class wxMacEventLoopSource
: public wxEventLoopSourceBase
<CFRunLoopSourceRef
>
171 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
172 int GetFileDescriptor() const
178 wxMacEventLoopSource() : wxEventLoopSourceBase
<CFRunLoopSourceRef
>() { }
180 // ctor setting internal value to the os resource res
181 wxMacEventLoopSource(CFRunLoopSourceRef res
,
182 wxEventLoopSourceHandler
* handler
, int flags
) :
183 wxEventLoopSourceBase
<CFRunLoopSourceRef
>(res
, handler
, flags
)
187 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
191 friend class wxGUIEventLoop
;
195 #if defined(__UNIX__)
196 class wxUnixEventLoopSource
: public wxEventLoopSourceBase
<int>
199 wxUnixEventLoopSource() : wxEventLoopSourceBase
<int>() { }
201 // ctor setting internal value to the os resource res
202 wxUnixEventLoopSource(int res
, wxEventLoopSourceHandler
* handler
,
204 wxEventLoopSourceBase
<int>(res
, handler
, flags
)
208 friend class wxConsoleEventLoop
;
209 friend class wxGUIEventLoop
;
213 // the list of watched sources
214 WX_DECLARE_HASH_SET(wxAbstractEventLoopSource
*, wxPointerHash
, wxPointerEqual
,
215 wxEventLoopSourceHashSet
);
221 NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
222 ------------------------------------------
224 The YieldFor() function helps to avoid re-entrancy problems and problems
225 caused by out-of-order event processing
226 (see "wxYield-like problems" and "wxProgressDialog+threading BUG" wx-dev threads).
228 The logic behind YieldFor() is simple: it analyzes the queue of the native
229 events generated by the underlying GUI toolkit and picks out and processes
230 only those matching the given mask.
232 It's important to note that YieldFor() is used to selectively process the
233 events generated by the NATIVE toolkit.
234 Events syntethized by wxWidgets code or by user code are instead selectively
235 processed thanks to the logic built into wxEvtHandler::ProcessPendingEvents().
236 In fact, when wxEvtHandler::ProcessPendingEvents gets called from inside a
237 YieldFor() call, wxEventLoopBase::IsEventAllowedInsideYield is used to decide
238 if the pending events for that event handler can be processed.
239 If all the pending events associated with that event handler result as "not processable",
240 the event handler "delays" itself calling wxEventLoopBase::DelayPendingEventHandler
241 (so it's moved: m_handlersWithPendingEvents => m_handlersWithPendingDelayedEvents).
242 Last, wxEventLoopBase::ProcessPendingEvents() before exiting moves the delayed
243 event handlers back into the list of handlers with pending events
244 (m_handlersWithPendingDelayedEvents => m_handlersWithPendingEvents) so that
245 a later call to ProcessPendingEvents() (possibly outside the YieldFor() call)
246 will process all pending events as usual.
249 // ----------------------------------------------------------------------------
250 // wxEventLoopBase: interface for wxEventLoop
251 // ----------------------------------------------------------------------------
253 class WXDLLIMPEXP_BASE wxEventLoopBase
256 // trivial, but needed (because of wxEventLoopBase) ctor
260 virtual ~wxEventLoopBase() { }
262 // use this to check whether the event loop was successfully created before
264 virtual bool IsOk() const { return true; }
266 // returns true if this is the main loop
269 #if wxUSE_EVENTLOOP_SOURCE
270 virtual wxAbstractEventLoopSource
* CreateSource() const = 0;
272 virtual wxAbstractEventLoopSource
* CreateSource(int WXUNUSED(res
),
273 wxEventLoopSourceHandler
* WXUNUSED(handler
),
274 int WXUNUSED(flags
)) const
279 // adds source to be monitored for I/O events specified in flags. Upon an
280 // event the appropriate method of handler will be called. The handler is
281 // owned be the calling client and will not be freed in any case.
282 // Returns true if the source was successfully added, false if it failed
283 // (this may happen for example when this source is already monitored)
284 virtual bool AddSource(wxAbstractEventLoopSource
* source
)
286 wxCHECK_MSG( source
&& source
->IsOk(), false, "Invalid source" );
288 wxEventLoopSourceHashSet::value_type
val(source
);
289 if (!m_sourceMap
.insert(val
).second
)
294 bool ret
= DoAddSource(source
);
297 (void) m_sourceMap
.erase(source
);
302 // removes the source from the list of monitored sources.
303 // Returns true if the source was successfully removed, false otherwise
304 virtual bool RemoveSource(wxAbstractEventLoopSource
* source
)
306 wxCHECK_MSG( source
&& source
->IsOk(), false, "Invalid source" );
308 if (m_sourceMap
.find(source
) == m_sourceMap
.end())
313 bool ret
= DoRemoveSource(source
);
314 m_sourceMap
.erase(source
);
318 bool RemoveAllSources()
320 wxEventLoopSourceHashSet::iterator it
= m_sourceMap
.begin();
321 while ( !m_sourceMap
.empty() )
323 (void) RemoveSource(*it
);
324 m_sourceMap
.erase(it
);
325 it
= m_sourceMap
.begin();
332 // dispatch&processing
333 // -------------------
335 // start the event loop, return the exit code when it is finished
336 virtual int Run() = 0;
338 // is this event loop running now?
340 // notice that even if this event loop hasn't terminated yet but has just
341 // spawned a nested (e.g. modal) event loop, this would return false
342 bool IsRunning() const;
344 // exit from the loop with the given exit code
345 virtual void Exit(int rc
= 0) = 0;
347 // return true if any events are available
348 virtual bool Pending() const = 0;
350 // dispatch a single event, return false if we should exit from the loop
351 virtual bool Dispatch() = 0;
353 // same as Dispatch() but doesn't wait for longer than the specified (in
354 // ms) timeout, return true if an event was processed, false if we should
355 // exit the loop or -1 if timeout expired
356 virtual int DispatchTimeout(unsigned long timeout
) = 0;
358 // implement this to wake up the loop: usually done by posting a dummy event
359 // to it (can be called from non main thread)
360 virtual void WakeUp() = 0;
366 // make sure that idle events are sent again
367 virtual void WakeUpIdle();
369 // this virtual function is called when the application
370 // becomes idle and by default it forwards to wxApp::ProcessIdle() and
371 // while it can be overridden in a custom event loop, you must call the
372 // base class version to ensure that idle events are still generated
374 // it should return true if more idle events are needed, false if not
375 virtual bool ProcessIdle();
378 // Yield-related hooks
379 // -------------------
381 // process all currently pending events right now
383 // it is an error to call Yield() recursively unless the value of
384 // onlyIfNeeded is true
386 // WARNING: this function is dangerous as it can lead to unexpected
387 // reentrancies (i.e. when called from an event handler it
388 // may result in calling the same event handler again), use
389 // with _extreme_ care or, better, don't use at all!
390 bool Yield(bool onlyIfNeeded
= false);
391 virtual bool YieldFor(long eventsToProcess
) = 0;
393 // returns true if the main thread is inside a Yield() call
394 virtual bool IsYielding() const
395 { return m_isInsideYield
; }
397 // returns true if events of the given event category should be immediately
398 // processed inside a wxApp::Yield() call or rather should be queued for
399 // later processing by the main event loop
400 virtual bool IsEventAllowedInsideYield(wxEventCategory cat
) const
401 { return (m_eventsToProcessInsideYield
& cat
) != 0; }
403 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
409 // return currently active (running) event loop, may be NULL
410 static wxEventLoopBase
*GetActive() { return ms_activeLoop
; }
412 // set currently active (running) event loop
413 static void SetActive(wxEventLoopBase
* loop
);
417 #if wxUSE_EVENTLOOP_SOURCE
418 virtual bool DoAddSource(wxAbstractEventLoopSource
* source
) = 0;
419 virtual bool DoRemoveSource(wxAbstractEventLoopSource
* source
) = 0;
421 wxEventLoopSourceHashSet m_sourceMap
;
424 // this function should be called before the event loop terminates, whether
425 // this happens normally (because of Exit() call) or abnormally (because of
426 // an exception thrown from inside the loop)
427 virtual void OnExit();
429 // the pointer to currently active loop
430 static wxEventLoopBase
*ms_activeLoop
;
432 // YieldFor() helpers:
433 bool m_isInsideYield
;
434 long m_eventsToProcessInsideYield
;
436 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase
);
439 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || defined(__UNIX__)
441 // this class can be used to implement a standard event loop logic using
442 // Pending() and Dispatch()
444 // it also handles idle processing automatically
445 class WXDLLIMPEXP_BASE wxEventLoopManual
: public wxEventLoopBase
450 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
451 // terminating when Exit() is called
454 // sets the "should exit" flag and wakes up the loop so that it terminates
456 virtual void Exit(int rc
= 0);
459 // may be overridden to perform some action at the start of each new event
461 virtual void OnNextIteration() { }
464 // the loop exit code
467 // should we exit the loop?
471 // process all already pending events and dispatch a new one (blocking
472 // until it appears in the event queue if necessary)
474 // returns the return value of Dispatch()
475 bool ProcessEvents();
477 wxDECLARE_NO_COPY_CLASS(wxEventLoopManual
);
480 #endif // platforms using "manual" loop
482 // we're moving away from old m_impl wxEventLoop model as otherwise the user
483 // code doesn't have access to platform-specific wxEventLoop methods and this
484 // can sometimes be very useful (e.g. under MSW this is necessary for
485 // integration with MFC) but currently this is done for MSW only, other ports
486 // should follow a.s.a.p.
487 #if defined(__WXPALMOS__)
488 #include "wx/palmos/evtloop.h"
489 #elif defined(__WXMSW__)
490 #include "wx/msw/evtloop.h"
491 #elif defined(__WXMAC__)
492 #include "wx/osx/evtloop.h"
493 #elif defined(__WXCOCOA__)
494 #include "wx/cocoa/evtloop.h"
495 #elif defined(__WXDFB__)
496 #include "wx/dfb/evtloop.h"
497 #elif defined(__WXGTK__)
498 #include "wx/gtk/evtloop.h"
499 #else // other platform
501 #include "wx/stopwatch.h" // for wxMilliClock_t
503 class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl
;
505 class WXDLLIMPEXP_CORE wxGUIEventLoop
: public wxEventLoopBase
508 wxGUIEventLoop() { m_impl
= NULL
; }
509 virtual ~wxGUIEventLoop();
512 virtual void Exit(int rc
= 0);
513 virtual bool Pending() const;
514 virtual bool Dispatch();
515 virtual int DispatchTimeout(unsigned long timeout
)
517 // TODO: this is, of course, horribly inefficient and a proper wait with
518 // timeout should be implemented for all ports natively...
519 const wxMilliClock_t timeEnd
= wxGetLocalTimeMillis() + timeout
;
525 if ( wxGetLocalTimeMillis() >= timeEnd
)
529 virtual void WakeUp() { }
530 virtual bool YieldFor(long eventsToProcess
);
533 // the pointer to the port specific implementation class
534 wxEventLoopImpl
*m_impl
;
536 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop
);
541 // also include the header defining wxConsoleEventLoop for Unix systems
542 #if defined(__UNIX__)
543 #include "wx/unix/evtloop.h"
546 // we use a class rather than a typedef because wxEventLoop is forward-declared
549 class wxEventLoop
: public wxGUIEventLoop
{ };
551 // we can't define wxEventLoop differently in GUI and base libraries so use
552 // a #define to still allow writing wxEventLoop in the user code
553 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WXMSW__) || defined(__UNIX__))
554 #define wxEventLoop wxConsoleEventLoop
555 #else // we still must define it somehow for the code below...
556 #define wxEventLoop wxEventLoopBase
560 inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
563 // ----------------------------------------------------------------------------
565 // ----------------------------------------------------------------------------
567 // this is a naive generic implementation which uses wxWindowDisabler to
568 // implement modality, we will surely need platform-specific implementations
569 // too, this generic implementation is here only temporarily to see how it
571 class WXDLLIMPEXP_CORE wxModalEventLoop
: public wxGUIEventLoop
574 wxModalEventLoop(wxWindow
*winModal
)
576 m_windowDisabler
= new wxWindowDisabler(winModal
);
580 virtual void OnExit()
582 delete m_windowDisabler
;
583 m_windowDisabler
= NULL
;
585 wxGUIEventLoop::OnExit();
589 wxWindowDisabler
*m_windowDisabler
;
594 // ----------------------------------------------------------------------------
595 // wxEventLoopActivator: helper class for wxEventLoop implementations
596 // ----------------------------------------------------------------------------
598 // this object sets the wxEventLoop given to the ctor as the currently active
599 // one and unsets it in its dtor, this is especially useful in presence of
600 // exceptions but is more tidy even when we don't use them
601 class wxEventLoopActivator
604 wxEventLoopActivator(wxEventLoopBase
*evtLoop
)
606 m_evtLoopOld
= wxEventLoopBase::GetActive();
607 wxEventLoopBase::SetActive(evtLoop
);
610 ~wxEventLoopActivator()
612 // restore the previously active event loop
613 wxEventLoopBase::SetActive(m_evtLoopOld
);
617 wxEventLoopBase
*m_evtLoopOld
;
620 #if wxUSE_CONSOLE_EVENTLOOP
622 class wxEventLoopGuarantor
625 wxEventLoopGuarantor()
628 if (!wxEventLoop::GetActive())
630 m_evtLoopNew
= new wxEventLoop
;
631 wxEventLoop::SetActive(m_evtLoopNew
);
635 ~wxEventLoopGuarantor()
639 wxEventLoop::SetActive(NULL
);
645 wxEventLoop
*m_evtLoopNew
;
648 #endif // wxUSE_CONSOLE_EVENTLOOP
650 #endif // _WX_EVTLOOP_H_