]> git.saurik.com Git - wxWidgets.git/blame - src/common/evtloopcmn.cpp
remove old hacks for gtk blit problem which was probably fixed long ago
[wxWidgets.git] / src / common / evtloopcmn.cpp
CommitLineData
c8026dea
VZ
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
c8026dea
VZ
12// for compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
1e04d2bf
PC
19#include "wx/evtloop.h"
20
670f9935
WS
21#ifndef WX_PRECOMP
22 #include "wx/app.h"
23#endif //WX_PRECOMP
c8026dea
VZ
24
25// ----------------------------------------------------------------------------
26// globals
27// ----------------------------------------------------------------------------
28
2ddff00c 29wxEventLoopBase *wxEventLoopBase::ms_activeLoop = NULL;
c8026dea 30
dde19c21
FM
31wxEventLoopBase::wxEventLoopBase()
32{
33 m_isInsideYield = false;
34 m_eventsToProcessInsideYield = wxEVT_CATEGORY_ALL;
35}
36
37void 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
51void 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
78void 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
88bool 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
99void wxEventLoopBase::SuspendProcessingOfPendingEvents()
100{
101 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
102}
103
104void wxEventLoopBase::ResumeProcessingOfPendingEvents()
105{
106 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
107}
108
109void 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.
ee32a48d 122 wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker);
dde19c21
FM
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
ee32a48d 130 wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker);
dde19c21
FM
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
147void wxEventLoopBase::WakeUpIdle()
148{
149 WakeUp();
150}
151
152bool 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
164bool 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
52c9b349 179// wxEventLoopManual is unused in the other ports
2e38bcd2 180#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || (defined(__UNIX__) && wxUSE_BASE)
52c9b349 181
c8026dea
VZ
182// ============================================================================
183// wxEventLoopManual implementation
184// ============================================================================
185
186wxEventLoopManual::wxEventLoopManual()
187{
188 m_exitcode = 0;
189 m_shouldExit = false;
190}
191
192int 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
b46b1d59 200 wxEventLoopActivator activate(this);
c8026dea
VZ
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
275void 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
b3c86150 295#endif // __WXMSW__ || __WXMAC__ || __WXDFB__
9af42efd 296