]> git.saurik.com Git - wxWidgets.git/blame - include/wx/evtloop.h
Make wxChoice and wxComboBox behaviour same as in native controls in wxMSW.
[wxWidgets.git] / include / wx / evtloop.h
CommitLineData
3808e191
JS
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>
65571936 9// Licence: wxWindows licence
3808e191
JS
10///////////////////////////////////////////////////////////////////////////////
11
12#ifndef _WX_EVTLOOP_H_
13#define _WX_EVTLOOP_H_
14
1e04d2bf 15#include "wx/event.h"
752464f9 16#include "wx/utils.h"
6b8ef0b3 17
5cd99866
VZ
18// TODO: implement wxEventLoopSource for MSW (it should wrap a HANDLE and be
19// monitored using MsgWaitForMultipleObjects())
acbed114 20#if defined(__WXOSX__) || (defined(__UNIX__) && !defined(__WXMSW__))
6b8ef0b3
VZ
21 #define wxUSE_EVENTLOOP_SOURCE 1
22#else
23 #define wxUSE_EVENTLOOP_SOURCE 0
24#endif
25
26#if wxUSE_EVENTLOOP_SOURCE
5cd99866
VZ
27 class wxEventLoopSource;
28 class wxEventLoopSourceHandler;
6b8ef0b3
VZ
29#endif
30
dde19c21
FM
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
3808e191 60// ----------------------------------------------------------------------------
b46b1d59 61// wxEventLoopBase: interface for wxEventLoop
3808e191
JS
62// ----------------------------------------------------------------------------
63
b46b1d59 64class WXDLLIMPEXP_BASE wxEventLoopBase
3808e191
JS
65{
66public:
3754265e 67 // trivial, but needed (because of wxEventLoopBase) ctor
dde19c21 68 wxEventLoopBase();
3808e191
JS
69
70 // dtor
3754265e 71 virtual ~wxEventLoopBase() { }
3808e191 72
b46b1d59
VZ
73 // use this to check whether the event loop was successfully created before
74 // using it
75 virtual bool IsOk() const { return true; }
76
ec38d07d
FM
77 // returns true if this is the main loop
78 bool IsMain() const;
79
6b8ef0b3 80#if wxUSE_EVENTLOOP_SOURCE
5cd99866
VZ
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
9af42efd 86
dde19c21
FM
87 // dispatch&processing
88 // -------------------
89
3808e191 90 // start the event loop, return the exit code when it is finished
3754265e 91 virtual int Run() = 0;
3808e191 92
dde19c21
FM
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
3808e191 99 // exit from the loop with the given exit code
3754265e 100 virtual void Exit(int rc = 0) = 0;
3808e191 101
1a18887b 102 // return true if any events are available
3754265e 103 virtual bool Pending() const = 0;
3808e191 104
1a18887b 105 // dispatch a single event, return false if we should exit from the loop
3754265e 106 virtual bool Dispatch() = 0;
3808e191 107
9af42efd
VZ
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
dde19c21
FM
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
dde19c21
FM
118 // idle handling
119 // -------------
120
a758f601 121 // make sure that idle events are sent again
dde19c21
FM
122 virtual void WakeUpIdle();
123
124 // this virtual function is called when the application
a758f601
VZ
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
dde19c21
FM
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
6b8ef0b3
VZ
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!
dde19c21
FM
145 bool Yield(bool onlyIfNeeded = false);
146 virtual bool YieldFor(long eventsToProcess) = 0;
147
6b8ef0b3 148 // returns true if the main thread is inside a Yield() call
dde19c21
FM
149 virtual bool IsYielding() const
150 { return m_isInsideYield; }
151
6b8ef0b3
VZ
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
dde19c21
FM
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 // -----------
9af42efd 163
b9f246f7 164 // return currently active (running) event loop, may be NULL
2ddff00c 165 static wxEventLoopBase *GetActive() { return ms_activeLoop; }
3808e191 166
df0e1b64 167 // set currently active (running) event loop
ec38d07d 168 static void SetActive(wxEventLoopBase* loop);
df0e1b64 169
b46b1d59 170
3808e191 171protected:
4300caa7
VZ
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)
ec38d07d 175 virtual void OnExit();
4300caa7 176
b9f246f7 177 // the pointer to currently active loop
2ddff00c 178 static wxEventLoopBase *ms_activeLoop;
22f3361e 179
8e40ed85 180 // YieldFor() helpers:
dde19c21
FM
181 bool m_isInsideYield;
182 long m_eventsToProcessInsideYield;
183
c0c133e1 184 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
3754265e
VZ
185};
186
e27f5540 187#if defined(__WINDOWS__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && !defined(__WXOSX__))
c8026dea
VZ
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
b46b1d59 193class WXDLLIMPEXP_BASE wxEventLoopManual : public wxEventLoopBase
c8026dea
VZ
194{
195public:
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
5b87e74a 204 virtual void Exit(int rc = 0);
c8026dea
VZ
205
206protected:
c8026dea
VZ
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;
2a392e2d
VZ
217
218private:
26bacb82
VZ
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
2a392e2d 225 wxDECLARE_NO_COPY_CLASS(wxEventLoopManual);
c8026dea
VZ
226};
227
228#endif // platforms using "manual" loop
229
3754265e
VZ
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
5cd99866
VZ
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
da0ee16e 236#if defined(__DARWIN__)
5cd99866
VZ
237 // CoreFoundation-based event loop is currently in wxBase so include it in
238 // any case too (although maybe it actually shouldn't be there at all)
7ce6da52
VZ
239 #include "wx/osx/core/evtloop.h"
240#endif
241
242// include the header defining wxConsoleEventLoop
243#if defined(__UNIX__) && !defined(__WXMSW__)
244 #include "wx/unix/evtloop.h"
245#elif defined(__WINDOWS__)
246 #include "wx/msw/evtloopconsole.h"
247#endif
248
249#if wxUSE_GUI
5cd99866
VZ
250
251// include the appropriate header defining wxGUIEventLoop
252
e27f5540
VZ
253#if defined(__WXMSW__)
254 #include "wx/msw/evtloop.h"
255#elif defined(__WXCOCOA__)
1df4b194 256 #include "wx/cocoa/evtloop.h"
7ce6da52
VZ
257#elif defined(__WXOSX__)
258 #include "wx/osx/evtloop.h"
b3c86150
VS
259#elif defined(__WXDFB__)
260 #include "wx/dfb/evtloop.h"
bc7879ec 261#elif defined(__WXGTK20__)
564c7fc4 262 #include "wx/gtk/evtloop.h"
4d90072c 263#else // other platform
3754265e 264
9c26672d 265#include "wx/stopwatch.h" // for wxMilliClock_t
9af42efd 266
b5dbe15d 267class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
3754265e 268
53a2db12 269class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
3754265e
VZ
270{
271public:
b46b1d59
VZ
272 wxGUIEventLoop() { m_impl = NULL; }
273 virtual ~wxGUIEventLoop();
1a18887b 274
5d670c2c
VZ
275#if wxUSE_EVENTLOOP_SOURCE
276 // We need to define a base class pure virtual method but we can't provide
277 // a generic implementation for it so simply fail.
278 virtual wxEventLoopSource *
279 AddSourceForFD(int WXUNUSED(fd),
280 wxEventLoopSourceHandler * WXUNUSED(handler),
281 int WXUNUSED(flags))
282 {
283 wxFAIL_MSG( "support for event loop sources not implemented" );
284 return NULL;
285 }
286#endif // wxUSE_EVENTLOOP_SOURCE
287
3754265e
VZ
288 virtual int Run();
289 virtual void Exit(int rc = 0);
290 virtual bool Pending() const;
291 virtual bool Dispatch();
9c26672d
VZ
292 virtual int DispatchTimeout(unsigned long timeout)
293 {
294 // TODO: this is, of course, horribly inefficient and a proper wait with
295 // timeout should be implemented for all ports natively...
296 const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
297 for ( ;; )
298 {
299 if ( Pending() )
300 return Dispatch();
301
302 if ( wxGetLocalTimeMillis() >= timeEnd )
303 return -1;
304 }
305 }
b46b1d59 306 virtual void WakeUp() { }
dde19c21 307 virtual bool YieldFor(long eventsToProcess);
3754265e
VZ
308
309protected:
4300caa7
VZ
310 // the pointer to the port specific implementation class
311 wxEventLoopImpl *m_impl;
312
c0c133e1 313 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
4d90072c 314};
3754265e 315
4d90072c 316#endif // platforms
3808e191 317
5cd99866 318#endif // wxUSE_GUI
b46b1d59 319
b46b1d59 320#if wxUSE_GUI
5cd99866
VZ
321 // we use a class rather than a typedef because wxEventLoop is
322 // forward-declared in many places
2ddff00c 323 class wxEventLoop : public wxGUIEventLoop { };
5cd99866 324#else // !wxUSE_GUI
2ddff00c
VZ
325 // we can't define wxEventLoop differently in GUI and base libraries so use
326 // a #define to still allow writing wxEventLoop in the user code
e27f5540 327 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WINDOWS__) || defined(__UNIX__))
2ddff00c
VZ
328 #define wxEventLoop wxConsoleEventLoop
329 #else // we still must define it somehow for the code below...
330 #define wxEventLoop wxEventLoopBase
331 #endif
b46b1d59
VZ
332#endif
333
77fb1a02
VZ
334inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
335
80eee837 336#if wxUSE_GUI && !defined(__WXOSX__)
4300caa7
VZ
337// ----------------------------------------------------------------------------
338// wxModalEventLoop
339// ----------------------------------------------------------------------------
340
341// this is a naive generic implementation which uses wxWindowDisabler to
342// implement modality, we will surely need platform-specific implementations
343// too, this generic implementation is here only temporarily to see how it
344// works
53a2db12 345class WXDLLIMPEXP_CORE wxModalEventLoop : public wxGUIEventLoop
4300caa7
VZ
346{
347public:
348 wxModalEventLoop(wxWindow *winModal)
349 {
350 m_windowDisabler = new wxWindowDisabler(winModal);
351 }
352
353protected:
354 virtual void OnExit()
355 {
356 delete m_windowDisabler;
357 m_windowDisabler = NULL;
358
b46b1d59 359 wxGUIEventLoop::OnExit();
4300caa7
VZ
360 }
361
362private:
363 wxWindowDisabler *m_windowDisabler;
364};
365
b46b1d59
VZ
366#endif //wxUSE_GUI
367
77fb1a02
VZ
368// ----------------------------------------------------------------------------
369// wxEventLoopActivator: helper class for wxEventLoop implementations
370// ----------------------------------------------------------------------------
371
372// this object sets the wxEventLoop given to the ctor as the currently active
373// one and unsets it in its dtor, this is especially useful in presence of
374// exceptions but is more tidy even when we don't use them
375class wxEventLoopActivator
376{
377public:
b46b1d59 378 wxEventLoopActivator(wxEventLoopBase *evtLoop)
77fb1a02 379 {
b46b1d59 380 m_evtLoopOld = wxEventLoopBase::GetActive();
2ddff00c 381 wxEventLoopBase::SetActive(evtLoop);
77fb1a02
VZ
382 }
383
384 ~wxEventLoopActivator()
385 {
386 // restore the previously active event loop
b46b1d59 387 wxEventLoopBase::SetActive(m_evtLoopOld);
77fb1a02
VZ
388 }
389
390private:
2ddff00c 391 wxEventLoopBase *m_evtLoopOld;
77fb1a02
VZ
392};
393
1a7cfc94
VZ
394#if wxUSE_CONSOLE_EVENTLOOP
395
f212e222
SN
396class wxEventLoopGuarantor
397{
398public:
399 wxEventLoopGuarantor()
400 {
401 m_evtLoopNew = NULL;
402 if (!wxEventLoop::GetActive())
403 {
404 m_evtLoopNew = new wxEventLoop;
405 wxEventLoop::SetActive(m_evtLoopNew);
406 }
407 }
408
409 ~wxEventLoopGuarantor()
410 {
411 if (m_evtLoopNew)
412 {
413 wxEventLoop::SetActive(NULL);
414 delete m_evtLoopNew;
415 }
416 }
417
418private:
419 wxEventLoop *m_evtLoopNew;
420};
421
1a7cfc94
VZ
422#endif // wxUSE_CONSOLE_EVENTLOOP
423
3808e191 424#endif // _WX_EVTLOOP_H_