]> git.saurik.com Git - wxWidgets.git/blob - include/wx/evtloop.h
52084d997dec5d5d88bbeabec2e4be5364731651
[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 virtual void Exit(int rc = 0) = 0;
104
105 // return true if any events are available
106 virtual bool Pending() const = 0;
107
108 // dispatch a single event, return false if we should exit from the loop
109 virtual bool Dispatch() = 0;
110
111 // same as Dispatch() but doesn't wait for longer than the specified (in
112 // ms) timeout, return true if an event was processed, false if we should
113 // exit the loop or -1 if timeout expired
114 virtual int DispatchTimeout(unsigned long timeout) = 0;
115
116 // implement this to wake up the loop: usually done by posting a dummy event
117 // to it (can be called from non main thread)
118 virtual void WakeUp() = 0;
119
120
121 // idle handling
122 // -------------
123
124 // make sure that idle events are sent again
125 virtual void WakeUpIdle();
126
127 // this virtual function is called when the application
128 // becomes idle and by default it forwards to wxApp::ProcessIdle() and
129 // while it can be overridden in a custom event loop, you must call the
130 // base class version to ensure that idle events are still generated
131 //
132 // it should return true if more idle events are needed, false if not
133 virtual bool ProcessIdle();
134
135
136 // Yield-related hooks
137 // -------------------
138
139 // process all currently pending events right now
140 //
141 // it is an error to call Yield() recursively unless the value of
142 // onlyIfNeeded is true
143 //
144 // WARNING: this function is dangerous as it can lead to unexpected
145 // reentrancies (i.e. when called from an event handler it
146 // may result in calling the same event handler again), use
147 // with _extreme_ care or, better, don't use at all!
148 bool Yield(bool onlyIfNeeded = false);
149 virtual bool YieldFor(long eventsToProcess) = 0;
150
151 // returns true if the main thread is inside a Yield() call
152 virtual bool IsYielding() const
153 { return m_isInsideYield; }
154
155 // returns true if events of the given event category should be immediately
156 // processed inside a wxApp::Yield() call or rather should be queued for
157 // later processing by the main event loop
158 virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const
159 { return (m_eventsToProcessInsideYield & cat) != 0; }
160
161 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
162
163
164 // active loop
165 // -----------
166
167 // return currently active (running) event loop, may be NULL
168 static wxEventLoopBase *GetActive() { return ms_activeLoop; }
169
170 // set currently active (running) event loop
171 static void SetActive(wxEventLoopBase* loop);
172
173
174 protected:
175 // real implementation of Run()
176 virtual int DoRun() = 0;
177
178 // this function should be called before the event loop terminates, whether
179 // this happens normally (because of Exit() call) or abnormally (because of
180 // an exception thrown from inside the loop)
181 virtual void OnExit();
182
183 // the pointer to currently active loop
184 static wxEventLoopBase *ms_activeLoop;
185
186 // should we exit the loop?
187 bool m_shouldExit;
188
189 // YieldFor() helpers:
190 bool m_isInsideYield;
191 long m_eventsToProcessInsideYield;
192
193 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
194 };
195
196 #if defined(__WINDOWS__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && !defined(__WXOSX__))
197
198 // this class can be used to implement a standard event loop logic using
199 // Pending() and Dispatch()
200 //
201 // it also handles idle processing automatically
202 class WXDLLIMPEXP_BASE wxEventLoopManual : public wxEventLoopBase
203 {
204 public:
205 wxEventLoopManual();
206
207 // sets the "should exit" flag and wakes up the loop so that it terminates
208 // soon
209 virtual void Exit(int rc = 0);
210
211 protected:
212 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
213 // terminating when Exit() is called
214 virtual int DoRun();
215
216 // may be overridden to perform some action at the start of each new event
217 // loop iteration
218 virtual void OnNextIteration() { }
219
220
221 // the loop exit code
222 int m_exitcode;
223
224 private:
225 // process all already pending events and dispatch a new one (blocking
226 // until it appears in the event queue if necessary)
227 //
228 // returns the return value of Dispatch()
229 bool ProcessEvents();
230
231 wxDECLARE_NO_COPY_CLASS(wxEventLoopManual);
232 };
233
234 #endif // platforms using "manual" loop
235
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
241
242 #if defined(__DARWIN__)
243 // CoreFoundation-based event loop is currently in wxBase so include it in
244 // any case too (although maybe it actually shouldn't be there at all)
245 #include "wx/osx/core/evtloop.h"
246 #endif
247
248 // include the header defining wxConsoleEventLoop
249 #if defined(__UNIX__) && !defined(__WXMSW__)
250 #include "wx/unix/evtloop.h"
251 #elif defined(__WINDOWS__)
252 #include "wx/msw/evtloopconsole.h"
253 #endif
254
255 #if wxUSE_GUI
256
257 // include the appropriate header defining wxGUIEventLoop
258
259 #if defined(__WXMSW__)
260 #include "wx/msw/evtloop.h"
261 #elif defined(__WXCOCOA__)
262 #include "wx/cocoa/evtloop.h"
263 #elif defined(__WXOSX__)
264 #include "wx/osx/evtloop.h"
265 #elif defined(__WXDFB__)
266 #include "wx/dfb/evtloop.h"
267 #elif defined(__WXGTK20__)
268 #include "wx/gtk/evtloop.h"
269 #else // other platform
270
271 #include "wx/stopwatch.h" // for wxMilliClock_t
272
273 class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
274
275 class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
276 {
277 public:
278 wxGUIEventLoop() { m_impl = NULL; }
279 virtual ~wxGUIEventLoop();
280
281 #if wxUSE_EVENTLOOP_SOURCE
282 // We need to define a base class pure virtual method but we can't provide
283 // a generic implementation for it so simply fail.
284 virtual wxEventLoopSource *
285 AddSourceForFD(int WXUNUSED(fd),
286 wxEventLoopSourceHandler * WXUNUSED(handler),
287 int WXUNUSED(flags))
288 {
289 wxFAIL_MSG( "support for event loop sources not implemented" );
290 return NULL;
291 }
292 #endif // wxUSE_EVENTLOOP_SOURCE
293
294 virtual void Exit(int rc = 0);
295 virtual bool Pending() const;
296 virtual bool Dispatch();
297 virtual int DispatchTimeout(unsigned long timeout)
298 {
299 // TODO: this is, of course, horribly inefficient and a proper wait with
300 // timeout should be implemented for all ports natively...
301 const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
302 for ( ;; )
303 {
304 if ( Pending() )
305 return Dispatch();
306
307 if ( wxGetLocalTimeMillis() >= timeEnd )
308 return -1;
309 }
310 }
311 virtual void WakeUp() { }
312 virtual bool YieldFor(long eventsToProcess);
313
314 protected:
315 virtual int DoRun();
316
317 // the pointer to the port specific implementation class
318 wxEventLoopImpl *m_impl;
319
320 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
321 };
322
323 #endif // platforms
324
325 #endif // wxUSE_GUI
326
327 #if wxUSE_GUI
328 // we use a class rather than a typedef because wxEventLoop is
329 // forward-declared in many places
330 class wxEventLoop : public wxGUIEventLoop { };
331 #else // !wxUSE_GUI
332 // we can't define wxEventLoop differently in GUI and base libraries so use
333 // a #define to still allow writing wxEventLoop in the user code
334 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WINDOWS__) || defined(__UNIX__))
335 #define wxEventLoop wxConsoleEventLoop
336 #else // we still must define it somehow for the code below...
337 #define wxEventLoop wxEventLoopBase
338 #endif
339 #endif
340
341 inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
342
343 #if wxUSE_GUI && !defined(__WXOSX__)
344 // ----------------------------------------------------------------------------
345 // wxModalEventLoop
346 // ----------------------------------------------------------------------------
347
348 // this is a naive generic implementation which uses wxWindowDisabler to
349 // implement modality, we will surely need platform-specific implementations
350 // too, this generic implementation is here only temporarily to see how it
351 // works
352 class WXDLLIMPEXP_CORE wxModalEventLoop : public wxGUIEventLoop
353 {
354 public:
355 wxModalEventLoop(wxWindow *winModal)
356 {
357 m_windowDisabler = new wxWindowDisabler(winModal);
358 }
359
360 protected:
361 virtual void OnExit()
362 {
363 delete m_windowDisabler;
364 m_windowDisabler = NULL;
365
366 wxGUIEventLoop::OnExit();
367 }
368
369 private:
370 wxWindowDisabler *m_windowDisabler;
371 };
372
373 #endif //wxUSE_GUI
374
375 // ----------------------------------------------------------------------------
376 // wxEventLoopActivator: helper class for wxEventLoop implementations
377 // ----------------------------------------------------------------------------
378
379 // this object sets the wxEventLoop given to the ctor as the currently active
380 // one and unsets it in its dtor, this is especially useful in presence of
381 // exceptions but is more tidy even when we don't use them
382 class wxEventLoopActivator
383 {
384 public:
385 wxEventLoopActivator(wxEventLoopBase *evtLoop)
386 {
387 m_evtLoopOld = wxEventLoopBase::GetActive();
388 wxEventLoopBase::SetActive(evtLoop);
389 }
390
391 ~wxEventLoopActivator()
392 {
393 // restore the previously active event loop
394 wxEventLoopBase::SetActive(m_evtLoopOld);
395 }
396
397 private:
398 wxEventLoopBase *m_evtLoopOld;
399 };
400
401 #if wxUSE_CONSOLE_EVENTLOOP
402
403 class wxEventLoopGuarantor
404 {
405 public:
406 wxEventLoopGuarantor()
407 {
408 m_evtLoopNew = NULL;
409 if (!wxEventLoop::GetActive())
410 {
411 m_evtLoopNew = new wxEventLoop;
412 wxEventLoop::SetActive(m_evtLoopNew);
413 }
414 }
415
416 ~wxEventLoopGuarantor()
417 {
418 if (m_evtLoopNew)
419 {
420 wxEventLoop::SetActive(NULL);
421 delete m_evtLoopNew;
422 }
423 }
424
425 private:
426 wxEventLoop *m_evtLoopNew;
427 };
428
429 #endif // wxUSE_CONSOLE_EVENTLOOP
430
431 #endif // _WX_EVTLOOP_H_