]> git.saurik.com Git - wxWidgets.git/blob - include/wx/evtloop.h
Extract PipeIOHandler class into a header and rename to wxWakeUpPipe.
[wxWidgets.git] / include / wx / evtloop.h
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: wx/evtloop.h
3 // Purpose: declares wxEventLoop class
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 01.06.01
7 // RCS-ID: $Id$
8 // Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifndef _WX_EVTLOOP_H_
13 #define _WX_EVTLOOP_H_
14
15 #include "wx/event.h"
16 #include "wx/utils.h"
17
18 // TODO: implement wxEventLoopSource for MSW (it should wrap a HANDLE and be
19 // monitored using MsgWaitForMultipleObjects())
20 #if defined(__WXOSX__) || (defined(__UNIX__) && !defined(__WXMSW__))
21 #define wxUSE_EVENTLOOP_SOURCE 1
22 #else
23 #define wxUSE_EVENTLOOP_SOURCE 0
24 #endif
25
26 #if wxUSE_EVENTLOOP_SOURCE
27 class wxEventLoopSource;
28 class wxEventLoopSourceHandler;
29 #endif
30
31 /*
32 NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
33 ------------------------------------------
34
35 The YieldFor() function helps to avoid re-entrancy problems and problems
36 caused by out-of-order event processing
37 (see "wxYield-like problems" and "wxProgressDialog+threading BUG" wx-dev threads).
38
39 The logic behind YieldFor() is simple: it analyzes the queue of the native
40 events generated by the underlying GUI toolkit and picks out and processes
41 only those matching the given mask.
42
43 It's important to note that YieldFor() is used to selectively process the
44 events generated by the NATIVE toolkit.
45 Events syntethized by wxWidgets code or by user code are instead selectively
46 processed thanks to the logic built into wxEvtHandler::ProcessPendingEvents().
47 In fact, when wxEvtHandler::ProcessPendingEvents gets called from inside a
48 YieldFor() call, wxEventLoopBase::IsEventAllowedInsideYield is used to decide
49 if the pending events for that event handler can be processed.
50 If all the pending events associated with that event handler result as "not processable",
51 the event handler "delays" itself calling wxEventLoopBase::DelayPendingEventHandler
52 (so it's moved: m_handlersWithPendingEvents => m_handlersWithPendingDelayedEvents).
53 Last, wxEventLoopBase::ProcessPendingEvents() before exiting moves the delayed
54 event handlers back into the list of handlers with pending events
55 (m_handlersWithPendingDelayedEvents => m_handlersWithPendingEvents) so that
56 a later call to ProcessPendingEvents() (possibly outside the YieldFor() call)
57 will process all pending events as usual.
58 */
59
60 // ----------------------------------------------------------------------------
61 // wxEventLoopBase: interface for wxEventLoop
62 // ----------------------------------------------------------------------------
63
64 class WXDLLIMPEXP_BASE wxEventLoopBase
65 {
66 public:
67 // trivial, but needed (because of wxEventLoopBase) ctor
68 wxEventLoopBase();
69
70 // dtor
71 virtual ~wxEventLoopBase() { }
72
73 // use this to check whether the event loop was successfully created before
74 // using it
75 virtual bool IsOk() const { return true; }
76
77 // returns true if this is the main loop
78 bool IsMain() const;
79
80 #if wxUSE_EVENTLOOP_SOURCE
81 // create a new event loop source wrapping the given file descriptor and
82 // start monitoring it
83 virtual wxEventLoopSource *
84 AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags) = 0;
85 #endif // wxUSE_EVENTLOOP_SOURCE
86
87 // dispatch&processing
88 // -------------------
89
90 // start the event loop, return the exit code when it is finished
91 //
92 // notice that wx ports should override DoRun(), this method is virtual
93 // only to allow overriding it in the user code for custom event loops
94 virtual int Run();
95
96 // is this event loop running now?
97 //
98 // notice that even if this event loop hasn't terminated yet but has just
99 // spawned a nested (e.g. modal) event loop, this would return false
100 bool IsRunning() const;
101
102 // exit from the loop with the given exit code
103 //
104 // this can be only used to exit the currently running loop, use
105 // ScheduleExit() if this might not be the case
106 virtual void Exit(int rc = 0);
107
108 // ask the event loop to exit with the given exit code, can be used even if
109 // this loop is not running right now but the loop must have been started,
110 // i.e. Run() should have been already called
111 virtual void ScheduleExit(int rc = 0) = 0;
112
113 // return true if any events are available
114 virtual bool Pending() const = 0;
115
116 // dispatch a single event, return false if we should exit from the loop
117 virtual bool Dispatch() = 0;
118
119 // same as Dispatch() but doesn't wait for longer than the specified (in
120 // ms) timeout, return true if an event was processed, false if we should
121 // exit the loop or -1 if timeout expired
122 virtual int DispatchTimeout(unsigned long timeout) = 0;
123
124 // implement this to wake up the loop: usually done by posting a dummy event
125 // to it (can be called from non main thread)
126 virtual void WakeUp() = 0;
127
128
129 // idle handling
130 // -------------
131
132 // make sure that idle events are sent again
133 virtual void WakeUpIdle();
134
135 // this virtual function is called when the application
136 // becomes idle and by default it forwards to wxApp::ProcessIdle() and
137 // while it can be overridden in a custom event loop, you must call the
138 // base class version to ensure that idle events are still generated
139 //
140 // it should return true if more idle events are needed, false if not
141 virtual bool ProcessIdle();
142
143
144 // Yield-related hooks
145 // -------------------
146
147 // process all currently pending events right now
148 //
149 // it is an error to call Yield() recursively unless the value of
150 // onlyIfNeeded is true
151 //
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;
158
159 // returns true if the main thread is inside a Yield() call
160 virtual bool IsYielding() const
161 { return m_isInsideYield; }
162
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; }
168
169 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
170
171
172 // active loop
173 // -----------
174
175 // return currently active (running) event loop, may be NULL
176 static wxEventLoopBase *GetActive() { return ms_activeLoop; }
177
178 // set currently active (running) event loop
179 static void SetActive(wxEventLoopBase* loop);
180
181
182 protected:
183 // real implementation of Run()
184 virtual int DoRun() = 0;
185
186 // this function should be called before the event loop terminates, whether
187 // this happens normally (because of Exit() call) or abnormally (because of
188 // an exception thrown from inside the loop)
189 virtual void OnExit();
190
191 // Return true if we're currently inside our Run(), even if another nested
192 // event loop is currently running, unlike IsRunning() (which should have
193 // been really called IsActive() but it's too late to change this now).
194 bool IsInsideRun() const { return m_isInsideRun; }
195
196
197 // the pointer to currently active loop
198 static wxEventLoopBase *ms_activeLoop;
199
200 // should we exit the loop?
201 bool m_shouldExit;
202
203 // YieldFor() helpers:
204 bool m_isInsideYield;
205 long m_eventsToProcessInsideYield;
206
207 private:
208 // this flag is set on entry into Run() and reset before leaving it
209 bool m_isInsideRun;
210
211 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
212 };
213
214 #if defined(__WINDOWS__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && !defined(__WXOSX__))
215
216 // this class can be used to implement a standard event loop logic using
217 // Pending() and Dispatch()
218 //
219 // it also handles idle processing automatically
220 class WXDLLIMPEXP_BASE wxEventLoopManual : public wxEventLoopBase
221 {
222 public:
223 wxEventLoopManual();
224
225 // sets the "should exit" flag and wakes up the loop so that it terminates
226 // soon
227 virtual void ScheduleExit(int rc = 0);
228
229 protected:
230 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
231 // terminating when Exit() is called
232 virtual int DoRun();
233
234 // may be overridden to perform some action at the start of each new event
235 // loop iteration
236 virtual void OnNextIteration() { }
237
238
239 // the loop exit code
240 int m_exitcode;
241
242 private:
243 // process all already pending events and dispatch a new one (blocking
244 // until it appears in the event queue if necessary)
245 //
246 // returns the return value of Dispatch()
247 bool ProcessEvents();
248
249 wxDECLARE_NO_COPY_CLASS(wxEventLoopManual);
250 };
251
252 #endif // platforms using "manual" loop
253
254 // we're moving away from old m_impl wxEventLoop model as otherwise the user
255 // code doesn't have access to platform-specific wxEventLoop methods and this
256 // can sometimes be very useful (e.g. under MSW this is necessary for
257 // integration with MFC) but currently this is not done for all ports yet (e.g.
258 // wxX11) so fall back to the old wxGUIEventLoop definition below for them
259
260 #if defined(__DARWIN__)
261 // CoreFoundation-based event loop is currently in wxBase so include it in
262 // any case too (although maybe it actually shouldn't be there at all)
263 #include "wx/osx/core/evtloop.h"
264 #endif
265
266 // include the header defining wxConsoleEventLoop
267 #if defined(__UNIX__) && !defined(__WXMSW__)
268 #include "wx/unix/evtloop.h"
269 #elif defined(__WINDOWS__)
270 #include "wx/msw/evtloopconsole.h"
271 #endif
272
273 #if wxUSE_GUI
274
275 // include the appropriate header defining wxGUIEventLoop
276
277 #if defined(__WXMSW__)
278 #include "wx/msw/evtloop.h"
279 #elif defined(__WXCOCOA__)
280 #include "wx/cocoa/evtloop.h"
281 #elif defined(__WXOSX__)
282 #include "wx/osx/evtloop.h"
283 #elif defined(__WXDFB__)
284 #include "wx/dfb/evtloop.h"
285 #elif defined(__WXGTK20__)
286 #include "wx/gtk/evtloop.h"
287 #else // other platform
288
289 #include "wx/stopwatch.h" // for wxMilliClock_t
290
291 class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
292
293 class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
294 {
295 public:
296 wxGUIEventLoop() { m_impl = NULL; }
297 virtual ~wxGUIEventLoop();
298
299 #if wxUSE_EVENTLOOP_SOURCE
300 // We need to define a base class pure virtual method but we can't provide
301 // a generic implementation for it so simply fail.
302 virtual wxEventLoopSource *
303 AddSourceForFD(int WXUNUSED(fd),
304 wxEventLoopSourceHandler * WXUNUSED(handler),
305 int WXUNUSED(flags))
306 {
307 wxFAIL_MSG( "support for event loop sources not implemented" );
308 return NULL;
309 }
310 #endif // wxUSE_EVENTLOOP_SOURCE
311
312 virtual void ScheduleExit(int rc = 0);
313 virtual bool Pending() const;
314 virtual bool Dispatch();
315 virtual int DispatchTimeout(unsigned long timeout)
316 {
317 // TODO: this is, of course, horribly inefficient and a proper wait with
318 // timeout should be implemented for all ports natively...
319 const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
320 for ( ;; )
321 {
322 if ( Pending() )
323 return Dispatch();
324
325 if ( wxGetLocalTimeMillis() >= timeEnd )
326 return -1;
327 }
328 }
329 virtual void WakeUp() { }
330 virtual bool YieldFor(long eventsToProcess);
331
332 protected:
333 virtual int DoRun();
334
335 // the pointer to the port specific implementation class
336 wxEventLoopImpl *m_impl;
337
338 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
339 };
340
341 #endif // platforms
342
343 #endif // wxUSE_GUI
344
345 #if wxUSE_GUI
346 // we use a class rather than a typedef because wxEventLoop is
347 // forward-declared in many places
348 class wxEventLoop : public wxGUIEventLoop { };
349 #else // !wxUSE_GUI
350 // we can't define wxEventLoop differently in GUI and base libraries so use
351 // a #define to still allow writing wxEventLoop in the user code
352 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WINDOWS__) || defined(__UNIX__))
353 #define wxEventLoop wxConsoleEventLoop
354 #else // we still must define it somehow for the code below...
355 #define wxEventLoop wxEventLoopBase
356 #endif
357 #endif
358
359 inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
360
361 #if wxUSE_GUI && !defined(__WXOSX__)
362 // ----------------------------------------------------------------------------
363 // wxModalEventLoop
364 // ----------------------------------------------------------------------------
365
366 // this is a naive generic implementation which uses wxWindowDisabler to
367 // implement modality, we will surely need platform-specific implementations
368 // too, this generic implementation is here only temporarily to see how it
369 // works
370 class WXDLLIMPEXP_CORE wxModalEventLoop : public wxGUIEventLoop
371 {
372 public:
373 wxModalEventLoop(wxWindow *winModal)
374 {
375 m_windowDisabler = new wxWindowDisabler(winModal);
376 }
377
378 protected:
379 virtual void OnExit()
380 {
381 delete m_windowDisabler;
382 m_windowDisabler = NULL;
383
384 wxGUIEventLoop::OnExit();
385 }
386
387 private:
388 wxWindowDisabler *m_windowDisabler;
389 };
390
391 #endif //wxUSE_GUI
392
393 // ----------------------------------------------------------------------------
394 // wxEventLoopActivator: helper class for wxEventLoop implementations
395 // ----------------------------------------------------------------------------
396
397 // this object sets the wxEventLoop given to the ctor as the currently active
398 // one and unsets it in its dtor, this is especially useful in presence of
399 // exceptions but is more tidy even when we don't use them
400 class wxEventLoopActivator
401 {
402 public:
403 wxEventLoopActivator(wxEventLoopBase *evtLoop)
404 {
405 m_evtLoopOld = wxEventLoopBase::GetActive();
406 wxEventLoopBase::SetActive(evtLoop);
407 }
408
409 ~wxEventLoopActivator()
410 {
411 // restore the previously active event loop
412 wxEventLoopBase::SetActive(m_evtLoopOld);
413 }
414
415 private:
416 wxEventLoopBase *m_evtLoopOld;
417 };
418
419 #if wxUSE_CONSOLE_EVENTLOOP
420
421 class wxEventLoopGuarantor
422 {
423 public:
424 wxEventLoopGuarantor()
425 {
426 m_evtLoopNew = NULL;
427 if (!wxEventLoop::GetActive())
428 {
429 m_evtLoopNew = new wxEventLoop;
430 wxEventLoop::SetActive(m_evtLoopNew);
431 }
432 }
433
434 ~wxEventLoopGuarantor()
435 {
436 if (m_evtLoopNew)
437 {
438 wxEventLoop::SetActive(NULL);
439 delete m_evtLoopNew;
440 }
441 }
442
443 private:
444 wxEventLoop *m_evtLoopNew;
445 };
446
447 #endif // wxUSE_CONSOLE_EVENTLOOP
448
449 #endif // _WX_EVTLOOP_H_