deprecate the old TryValidator/Parent() and replace them with the new and documented...
[wxWidgets.git] / src / common / evtloopcmn.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/evtloopcmn.cpp
3 // Purpose: common wxEventLoop-related stuff
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 2006-01-12
7 // RCS-ID: $Id$
8 // Copyright: (c) 2006 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // for compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #include "wx/evtloop.h"
20
21 #ifndef WX_PRECOMP
22 #include "wx/app.h"
23 #endif //WX_PRECOMP
24
25 // ----------------------------------------------------------------------------
26 // wxEventLoopBase
27 // ----------------------------------------------------------------------------
28
29 wxEventLoopBase *wxEventLoopBase::ms_activeLoop = NULL;
30
31 wxEventLoopBase::wxEventLoopBase()
32 {
33 m_isInsideYield = false;
34 m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL;
35 }
36
37 bool wxEventLoopBase::IsMain() const
38 {
39 if (wxTheApp)
40 return wxTheApp->GetMainLoop() == this;
41 return false;
42 }
43
44 /* static */
45 void wxEventLoopBase::SetActive(wxEventLoopBase* loop)
46 {
47 ms_activeLoop = loop;
48
49 if (wxTheApp)
50 wxTheApp->OnEventLoopEnter(loop);
51 }
52
53 void wxEventLoopBase::OnExit()
54 {
55 if (wxTheApp)
56 wxTheApp->OnEventLoopExit(this);
57 }
58
59 void wxEventLoopBase::DelayPendingEventHandler(wxEvtHandler* toDelay)
60 {
61 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
62
63 // move the handler from the list of handlers with processable pending events
64 // to the list of handlers with pending events which needs to be processed later
65 m_handlersWithPendingEvents.Remove(toDelay);
66
67 if (m_handlersWithPendingDelayedEvents.Index(toDelay) == wxNOT_FOUND)
68 m_handlersWithPendingDelayedEvents.Add(toDelay);
69
70 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
71 }
72
73 void wxEventLoopBase::RemovePendingEventHandler(wxEvtHandler* toRemove)
74 {
75 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
76
77 if (m_handlersWithPendingEvents.Index(toRemove) != wxNOT_FOUND)
78 {
79 m_handlersWithPendingEvents.Remove(toRemove);
80
81 // check that the handler was present only once in the list
82 wxASSERT_MSG( m_handlersWithPendingEvents.Index(toRemove) == wxNOT_FOUND,
83 "Handler occurs twice in the m_handlersWithPendingEvents list!" );
84 }
85 //else: it wasn't in this list at all, it's ok
86
87 if (m_handlersWithPendingDelayedEvents.Index(toRemove) != wxNOT_FOUND)
88 {
89 m_handlersWithPendingDelayedEvents.Remove(toRemove);
90
91 // check that the handler was present only once in the list
92 wxASSERT_MSG( m_handlersWithPendingDelayedEvents.Index(toRemove) == wxNOT_FOUND,
93 "Handler occurs twice in m_handlersWithPendingDelayedEvents list!" );
94 }
95 //else: it wasn't in this list at all, it's ok
96
97 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
98 }
99
100 void wxEventLoopBase::AppendPendingEventHandler(wxEvtHandler* toAppend)
101 {
102 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
103
104 if ( m_handlersWithPendingEvents.Index(toAppend) == wxNOT_FOUND )
105 m_handlersWithPendingEvents.Add(toAppend);
106
107 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
108 }
109
110 bool wxEventLoopBase::HasPendingEvents() const
111 {
112 wxENTER_CRIT_SECT(const_cast<wxEventLoopBase*>(this)->m_handlersWithPendingEventsLocker);
113
114 bool has = !m_handlersWithPendingEvents.IsEmpty();
115
116 wxLEAVE_CRIT_SECT(const_cast<wxEventLoopBase*>(this)->m_handlersWithPendingEventsLocker);
117
118 return has;
119 }
120
121 void wxEventLoopBase::SuspendProcessingOfPendingEvents()
122 {
123 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
124 }
125
126 void wxEventLoopBase::ResumeProcessingOfPendingEvents()
127 {
128 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
129 }
130
131 void wxEventLoopBase::ProcessPendingEvents()
132 {
133 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
134
135 wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(),
136 "this helper list should be empty" );
137
138 // iterate until the list becomes empty: the handlers remove themselves
139 // from it when they don't have any more pending events
140 while (!m_handlersWithPendingEvents.IsEmpty())
141 {
142 // In ProcessPendingEvents(), new handlers might be added
143 // and we can safely leave the critical section here.
144 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
145
146 // NOTE: we always call ProcessPendingEvents() on the first event handler
147 // with pending events because handlers auto-remove themselves
148 // from this list (see RemovePendingEventHandler) if they have no
149 // more pending events.
150 m_handlersWithPendingEvents[0]->ProcessPendingEvents();
151
152 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
153 }
154
155 // now the wxHandlersWithPendingEvents is surely empty; however some event
156 // handlers may have moved themselves into wxHandlersWithPendingDelayedEvents
157 // because of a selective wxYield call in progress.
158 // Now we need to move them back to wxHandlersWithPendingEvents so the next
159 // call to this function has the chance of processing them:
160 if (!m_handlersWithPendingDelayedEvents.IsEmpty())
161 {
162 WX_APPEND_ARRAY(m_handlersWithPendingEvents, m_handlersWithPendingDelayedEvents);
163 m_handlersWithPendingDelayedEvents.Clear();
164 }
165
166 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
167 }
168
169 void wxEventLoopBase::WakeUpIdle()
170 {
171 WakeUp();
172 }
173
174 bool wxEventLoopBase::ProcessIdle()
175 {
176 // process pending wx events before sending idle events
177 ProcessPendingEvents();
178
179 wxIdleEvent event;
180
181 event.SetEventObject(wxTheApp);
182 wxTheApp->ProcessEvent(event);
183 return event.MoreRequested();
184 }
185
186 bool wxEventLoopBase::Yield(bool onlyIfNeeded)
187 {
188 if ( m_isInsideYield )
189 {
190 if ( !onlyIfNeeded )
191 {
192 wxFAIL_MSG( wxT("wxYield called recursively" ) );
193 }
194
195 return false;
196 }
197
198 return YieldFor(wxEVT_CATEGORY_ALL);
199 }
200
201 // wxEventLoopManual is unused in the other ports
202 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && wxUSE_BASE)
203
204 // ============================================================================
205 // wxEventLoopManual implementation
206 // ============================================================================
207
208 wxEventLoopManual::wxEventLoopManual()
209 {
210 m_exitcode = 0;
211 m_shouldExit = false;
212 }
213
214 int wxEventLoopManual::Run()
215 {
216 // event loops are not recursive, you need to create another loop!
217 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
218
219 // ProcessIdle() and Dispatch() below may throw so the code here should
220 // be exception-safe, hence we must use local objects for all actions we
221 // should undo
222 wxEventLoopActivator activate(this);
223
224 // we must ensure that OnExit() is called even if an exception is thrown
225 // from inside Dispatch() but we must call it from Exit() in normal
226 // situations because it is supposed to be called synchronously,
227 // wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or
228 // something similar here)
229 #if wxUSE_EXCEPTIONS
230 for ( ;; )
231 {
232 try
233 {
234 #endif // wxUSE_EXCEPTIONS
235
236 // this is the event loop itself
237 for ( ;; )
238 {
239 // give them the possibility to do whatever they want
240 OnNextIteration();
241
242 // generate and process idle events for as long as we don't
243 // have anything else to do
244 while ( !Pending() && (wxTheApp && wxTheApp->ProcessIdle()) )
245 ;
246
247 // if the "should exit" flag is set, the loop should terminate
248 // but not before processing any remaining messages so while
249 // Pending() returns true, do process them
250 if ( m_shouldExit )
251 {
252 while ( Pending() )
253 Dispatch();
254
255 break;
256 }
257
258 // a message came or no more idle processing to do, sit in
259 // Dispatch() waiting for the next message
260 if ( !Dispatch() )
261 {
262 // we got WM_QUIT
263 break;
264 }
265 }
266
267 #if wxUSE_EXCEPTIONS
268 // exit the outer loop as well
269 break;
270 }
271 catch ( ... )
272 {
273 try
274 {
275 if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() )
276 {
277 OnExit();
278 break;
279 }
280 //else: continue running the event loop
281 }
282 catch ( ... )
283 {
284 // OnException() throwed, possibly rethrowing the same
285 // exception again: very good, but we still need OnExit() to
286 // be called
287 OnExit();
288 throw;
289 }
290 }
291 }
292 #endif // wxUSE_EXCEPTIONS
293
294 return m_exitcode;
295 }
296
297 void wxEventLoopManual::Exit(int rc)
298 {
299 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
300
301 m_exitcode = rc;
302 m_shouldExit = true;
303
304 OnExit();
305
306 // all we have to do to exit from the loop is to (maybe) wake it up so that
307 // it can notice that Exit() had been called
308 //
309 // in particular, do *not* use here calls such as PostQuitMessage() (under
310 // MSW) which terminate the current event loop here because we're not sure
311 // that it is going to be processed by the correct event loop: it would be
312 // possible that another one is started and terminated by mistake if we do
313 // this
314 WakeUp();
315 }
316
317 #endif // __WXMSW__ || __WXMAC__ || __WXDFB__
318