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