]> git.saurik.com Git - wxWidgets.git/blame - include/wx/evtloop.h
Resolve GCC's 'type-punned pointer will break strict-aliasing rules' warning by break...
[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())
20#if defined(__WXOSX__) || defined(__WXGTK20__) || defined(__WXDFB__) || \
21 (!wxUSE_GUI && defined(__UNIX__))
6b8ef0b3
VZ
22 #define wxUSE_EVENTLOOP_SOURCE 1
23#else
24 #define wxUSE_EVENTLOOP_SOURCE 0
25#endif
26
27#if wxUSE_EVENTLOOP_SOURCE
5cd99866
VZ
28 class wxEventLoopSource;
29 class wxEventLoopSourceHandler;
6b8ef0b3
VZ
30#endif
31
dde19c21
FM
32/*
33 NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
34 ------------------------------------------
35
36 The YieldFor() function helps to avoid re-entrancy problems and problems
37 caused by out-of-order event processing
38 (see "wxYield-like problems" and "wxProgressDialog+threading BUG" wx-dev threads).
39
40 The logic behind YieldFor() is simple: it analyzes the queue of the native
41 events generated by the underlying GUI toolkit and picks out and processes
42 only those matching the given mask.
43
44 It's important to note that YieldFor() is used to selectively process the
45 events generated by the NATIVE toolkit.
46 Events syntethized by wxWidgets code or by user code are instead selectively
47 processed thanks to the logic built into wxEvtHandler::ProcessPendingEvents().
48 In fact, when wxEvtHandler::ProcessPendingEvents gets called from inside a
49 YieldFor() call, wxEventLoopBase::IsEventAllowedInsideYield is used to decide
50 if the pending events for that event handler can be processed.
51 If all the pending events associated with that event handler result as "not processable",
52 the event handler "delays" itself calling wxEventLoopBase::DelayPendingEventHandler
53 (so it's moved: m_handlersWithPendingEvents => m_handlersWithPendingDelayedEvents).
54 Last, wxEventLoopBase::ProcessPendingEvents() before exiting moves the delayed
55 event handlers back into the list of handlers with pending events
56 (m_handlersWithPendingDelayedEvents => m_handlersWithPendingEvents) so that
57 a later call to ProcessPendingEvents() (possibly outside the YieldFor() call)
58 will process all pending events as usual.
59*/
60
3808e191 61// ----------------------------------------------------------------------------
b46b1d59 62// wxEventLoopBase: interface for wxEventLoop
3808e191
JS
63// ----------------------------------------------------------------------------
64
b46b1d59 65class WXDLLIMPEXP_BASE wxEventLoopBase
3808e191
JS
66{
67public:
3754265e 68 // trivial, but needed (because of wxEventLoopBase) ctor
dde19c21 69 wxEventLoopBase();
3808e191
JS
70
71 // dtor
3754265e 72 virtual ~wxEventLoopBase() { }
3808e191 73
b46b1d59
VZ
74 // use this to check whether the event loop was successfully created before
75 // using it
76 virtual bool IsOk() const { return true; }
77
ec38d07d
FM
78 // returns true if this is the main loop
79 bool IsMain() const;
80
6b8ef0b3 81#if wxUSE_EVENTLOOP_SOURCE
5cd99866
VZ
82 // create a new event loop source wrapping the given file descriptor and
83 // start monitoring it
84 virtual wxEventLoopSource *
85 AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags) = 0;
86#endif // wxUSE_EVENTLOOP_SOURCE
9af42efd 87
dde19c21
FM
88 // dispatch&processing
89 // -------------------
90
3808e191 91 // start the event loop, return the exit code when it is finished
3754265e 92 virtual int Run() = 0;
3808e191 93
dde19c21
FM
94 // is this event loop running now?
95 //
96 // notice that even if this event loop hasn't terminated yet but has just
97 // spawned a nested (e.g. modal) event loop, this would return false
98 bool IsRunning() const;
99
3808e191 100 // exit from the loop with the given exit code
3754265e 101 virtual void Exit(int rc = 0) = 0;
3808e191 102
1a18887b 103 // return true if any events are available
3754265e 104 virtual bool Pending() const = 0;
3808e191 105
1a18887b 106 // dispatch a single event, return false if we should exit from the loop
3754265e 107 virtual bool Dispatch() = 0;
3808e191 108
9af42efd
VZ
109 // same as Dispatch() but doesn't wait for longer than the specified (in
110 // ms) timeout, return true if an event was processed, false if we should
111 // exit the loop or -1 if timeout expired
112 virtual int DispatchTimeout(unsigned long timeout) = 0;
113
dde19c21
FM
114 // implement this to wake up the loop: usually done by posting a dummy event
115 // to it (can be called from non main thread)
116 virtual void WakeUp() = 0;
117
118
dde19c21
FM
119 // idle handling
120 // -------------
121
a758f601 122 // make sure that idle events are sent again
dde19c21
FM
123 virtual void WakeUpIdle();
124
125 // this virtual function is called when the application
a758f601
VZ
126 // becomes idle and by default it forwards to wxApp::ProcessIdle() and
127 // while it can be overridden in a custom event loop, you must call the
128 // base class version to ensure that idle events are still generated
dde19c21
FM
129 //
130 // it should return true if more idle events are needed, false if not
131 virtual bool ProcessIdle();
132
133
134 // Yield-related hooks
135 // -------------------
136
6b8ef0b3
VZ
137 // process all currently pending events right now
138 //
139 // it is an error to call Yield() recursively unless the value of
140 // onlyIfNeeded is true
141 //
142 // WARNING: this function is dangerous as it can lead to unexpected
143 // reentrancies (i.e. when called from an event handler it
144 // may result in calling the same event handler again), use
145 // with _extreme_ care or, better, don't use at all!
dde19c21
FM
146 bool Yield(bool onlyIfNeeded = false);
147 virtual bool YieldFor(long eventsToProcess) = 0;
148
6b8ef0b3 149 // returns true if the main thread is inside a Yield() call
dde19c21
FM
150 virtual bool IsYielding() const
151 { return m_isInsideYield; }
152
6b8ef0b3
VZ
153 // returns true if events of the given event category should be immediately
154 // processed inside a wxApp::Yield() call or rather should be queued for
155 // later processing by the main event loop
dde19c21
FM
156 virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const
157 { return (m_eventsToProcessInsideYield & cat) != 0; }
158
159 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
160
161
162 // active loop
163 // -----------
9af42efd 164
b9f246f7 165 // return currently active (running) event loop, may be NULL
2ddff00c 166 static wxEventLoopBase *GetActive() { return ms_activeLoop; }
3808e191 167
df0e1b64 168 // set currently active (running) event loop
ec38d07d 169 static void SetActive(wxEventLoopBase* loop);
df0e1b64 170
b46b1d59 171
3808e191 172protected:
4300caa7
VZ
173 // this function should be called before the event loop terminates, whether
174 // this happens normally (because of Exit() call) or abnormally (because of
175 // an exception thrown from inside the loop)
ec38d07d 176 virtual void OnExit();
4300caa7 177
b9f246f7 178 // the pointer to currently active loop
2ddff00c 179 static wxEventLoopBase *ms_activeLoop;
22f3361e 180
8e40ed85 181 // YieldFor() helpers:
dde19c21
FM
182 bool m_isInsideYield;
183 long m_eventsToProcessInsideYield;
184
c0c133e1 185 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
3754265e
VZ
186};
187
80eee837 188#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && !defined(__WXOSX__))
c8026dea
VZ
189
190// this class can be used to implement a standard event loop logic using
191// Pending() and Dispatch()
192//
193// it also handles idle processing automatically
b46b1d59 194class WXDLLIMPEXP_BASE wxEventLoopManual : public wxEventLoopBase
c8026dea
VZ
195{
196public:
197 wxEventLoopManual();
198
199 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
200 // terminating when Exit() is called
201 virtual int Run();
202
203 // sets the "should exit" flag and wakes up the loop so that it terminates
204 // soon
5b87e74a 205 virtual void Exit(int rc = 0);
c8026dea
VZ
206
207protected:
c8026dea
VZ
208 // may be overridden to perform some action at the start of each new event
209 // loop iteration
210 virtual void OnNextIteration() { }
211
212
213 // the loop exit code
214 int m_exitcode;
215
216 // should we exit the loop?
217 bool m_shouldExit;
2a392e2d
VZ
218
219private:
26bacb82
VZ
220 // process all already pending events and dispatch a new one (blocking
221 // until it appears in the event queue if necessary)
222 //
223 // returns the return value of Dispatch()
224 bool ProcessEvents();
225
2a392e2d 226 wxDECLARE_NO_COPY_CLASS(wxEventLoopManual);
c8026dea
VZ
227};
228
229#endif // platforms using "manual" loop
230
3754265e
VZ
231// we're moving away from old m_impl wxEventLoop model as otherwise the user
232// code doesn't have access to platform-specific wxEventLoop methods and this
233// can sometimes be very useful (e.g. under MSW this is necessary for
5cd99866
VZ
234// integration with MFC) but currently this is not done for all ports yet (e.g.
235// wxX11) so fall back to the old wxGUIEventLoop definition below for them
236
4055ed82 237#if defined(__WXPALMOS__)
ffecfa5a
JS
238 #include "wx/palmos/evtloop.h"
239#elif defined(__WXMSW__)
5cd99866 240 // this header defines both console and GUI loops for MSW
3754265e 241 #include "wx/msw/evtloop.h"
5cd99866
VZ
242#elif defined(__WXOSX__)
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)
ef0e9220 245 #include "wx/osx/evtloop.h"
5cd99866
VZ
246#elif wxUSE_GUI
247
248// include the appropriate header defining wxGUIEventLoop
249
250#if defined(__WXCOCOA__)
1df4b194 251 #include "wx/cocoa/evtloop.h"
b3c86150
VS
252#elif defined(__WXDFB__)
253 #include "wx/dfb/evtloop.h"
bc7879ec 254#elif defined(__WXGTK20__)
564c7fc4 255 #include "wx/gtk/evtloop.h"
4d90072c 256#else // other platform
3754265e 257
9c26672d 258#include "wx/stopwatch.h" // for wxMilliClock_t
9af42efd 259
b5dbe15d 260class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
3754265e 261
53a2db12 262class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
3754265e
VZ
263{
264public:
b46b1d59
VZ
265 wxGUIEventLoop() { m_impl = NULL; }
266 virtual ~wxGUIEventLoop();
1a18887b 267
3754265e
VZ
268 virtual int Run();
269 virtual void Exit(int rc = 0);
270 virtual bool Pending() const;
271 virtual bool Dispatch();
9c26672d
VZ
272 virtual int DispatchTimeout(unsigned long timeout)
273 {
274 // TODO: this is, of course, horribly inefficient and a proper wait with
275 // timeout should be implemented for all ports natively...
276 const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
277 for ( ;; )
278 {
279 if ( Pending() )
280 return Dispatch();
281
282 if ( wxGetLocalTimeMillis() >= timeEnd )
283 return -1;
284 }
285 }
b46b1d59 286 virtual void WakeUp() { }
dde19c21 287 virtual bool YieldFor(long eventsToProcess);
3754265e
VZ
288
289protected:
4300caa7
VZ
290 // the pointer to the port specific implementation class
291 wxEventLoopImpl *m_impl;
292
c0c133e1 293 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
4d90072c 294};
3754265e 295
4d90072c 296#endif // platforms
3808e191 297
5cd99866 298#endif // wxUSE_GUI
b46b1d59 299
9aee1212
SC
300// include the header defining wxConsoleEventLoop for Unix systems
301#if defined(__UNIX__)
302#include "wx/unix/evtloop.h"
303#endif
304
b46b1d59 305#if wxUSE_GUI
5cd99866
VZ
306 // we use a class rather than a typedef because wxEventLoop is
307 // forward-declared in many places
2ddff00c 308 class wxEventLoop : public wxGUIEventLoop { };
5cd99866 309#else // !wxUSE_GUI
2ddff00c
VZ
310 // we can't define wxEventLoop differently in GUI and base libraries so use
311 // a #define to still allow writing wxEventLoop in the user code
1a7cfc94 312 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WXMSW__) || defined(__UNIX__))
2ddff00c
VZ
313 #define wxEventLoop wxConsoleEventLoop
314 #else // we still must define it somehow for the code below...
315 #define wxEventLoop wxEventLoopBase
316 #endif
b46b1d59
VZ
317#endif
318
77fb1a02
VZ
319inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
320
80eee837 321#if wxUSE_GUI && !defined(__WXOSX__)
4300caa7
VZ
322// ----------------------------------------------------------------------------
323// wxModalEventLoop
324// ----------------------------------------------------------------------------
325
326// this is a naive generic implementation which uses wxWindowDisabler to
327// implement modality, we will surely need platform-specific implementations
328// too, this generic implementation is here only temporarily to see how it
329// works
53a2db12 330class WXDLLIMPEXP_CORE wxModalEventLoop : public wxGUIEventLoop
4300caa7
VZ
331{
332public:
333 wxModalEventLoop(wxWindow *winModal)
334 {
335 m_windowDisabler = new wxWindowDisabler(winModal);
336 }
337
338protected:
339 virtual void OnExit()
340 {
341 delete m_windowDisabler;
342 m_windowDisabler = NULL;
343
b46b1d59 344 wxGUIEventLoop::OnExit();
4300caa7
VZ
345 }
346
347private:
348 wxWindowDisabler *m_windowDisabler;
349};
350
b46b1d59
VZ
351#endif //wxUSE_GUI
352
77fb1a02
VZ
353// ----------------------------------------------------------------------------
354// wxEventLoopActivator: helper class for wxEventLoop implementations
355// ----------------------------------------------------------------------------
356
357// this object sets the wxEventLoop given to the ctor as the currently active
358// one and unsets it in its dtor, this is especially useful in presence of
359// exceptions but is more tidy even when we don't use them
360class wxEventLoopActivator
361{
362public:
b46b1d59 363 wxEventLoopActivator(wxEventLoopBase *evtLoop)
77fb1a02 364 {
b46b1d59 365 m_evtLoopOld = wxEventLoopBase::GetActive();
2ddff00c 366 wxEventLoopBase::SetActive(evtLoop);
77fb1a02
VZ
367 }
368
369 ~wxEventLoopActivator()
370 {
371 // restore the previously active event loop
b46b1d59 372 wxEventLoopBase::SetActive(m_evtLoopOld);
77fb1a02
VZ
373 }
374
375private:
2ddff00c 376 wxEventLoopBase *m_evtLoopOld;
77fb1a02
VZ
377};
378
1a7cfc94
VZ
379#if wxUSE_CONSOLE_EVENTLOOP
380
f212e222
SN
381class wxEventLoopGuarantor
382{
383public:
384 wxEventLoopGuarantor()
385 {
386 m_evtLoopNew = NULL;
387 if (!wxEventLoop::GetActive())
388 {
389 m_evtLoopNew = new wxEventLoop;
390 wxEventLoop::SetActive(m_evtLoopNew);
391 }
392 }
393
394 ~wxEventLoopGuarantor()
395 {
396 if (m_evtLoopNew)
397 {
398 wxEventLoop::SetActive(NULL);
399 delete m_evtLoopNew;
400 }
401 }
402
403private:
404 wxEventLoop *m_evtLoopNew;
405};
406
1a7cfc94
VZ
407#endif // wxUSE_CONSOLE_EVENTLOOP
408
3808e191 409#endif // _WX_EVTLOOP_H_