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