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