]> git.saurik.com Git - wxWidgets.git/blame - include/wx/evtloop.h
fix evtloop.h header dependency
[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
9af42efd 64
dde19c21
FM
65 // dispatch&processing
66 // -------------------
67
3808e191 68 // start the event loop, return the exit code when it is finished
3754265e 69 virtual int Run() = 0;
3808e191 70
dde19c21
FM
71 // is this event loop running now?
72 //
73 // notice that even if this event loop hasn't terminated yet but has just
74 // spawned a nested (e.g. modal) event loop, this would return false
75 bool IsRunning() const;
76
3808e191 77 // exit from the loop with the given exit code
3754265e 78 virtual void Exit(int rc = 0) = 0;
3808e191 79
1a18887b 80 // return true if any events are available
3754265e 81 virtual bool Pending() const = 0;
3808e191 82
1a18887b 83 // dispatch a single event, return false if we should exit from the loop
3754265e 84 virtual bool Dispatch() = 0;
3808e191 85
9af42efd
VZ
86 // same as Dispatch() but doesn't wait for longer than the specified (in
87 // ms) timeout, return true if an event was processed, false if we should
88 // exit the loop or -1 if timeout expired
89 virtual int DispatchTimeout(unsigned long timeout) = 0;
90
dde19c21
FM
91 // implement this to wake up the loop: usually done by posting a dummy event
92 // to it (can be called from non main thread)
93 virtual void WakeUp() = 0;
94
95
96 // pending events
97 // --------------
98
99 // process all events in the wxHandlersWithPendingEvents list -- it is necessary
100 // to call this function to process posted events. This happens during each
101 // event loop iteration in GUI mode but if there is no main loop, it may be
102 // also called directly.
103 virtual void ProcessPendingEvents();
104
105 // check if there are pending events on global pending event list
106 bool HasPendingEvents() const;
107
108 // temporary suspends processing of the pending events
109 void SuspendProcessingOfPendingEvents();
110
111 // resume processing of the pending events previously stopped because of a
112 // call to SuspendProcessingOfPendingEvents()
113 void ResumeProcessingOfPendingEvents();
114
115 // called by ~wxEvtHandler to (eventually) remove the handler from the list of
116 // the handlers with pending events
117 void RemovePendingEventHandler(wxEvtHandler* toRemove);
118
119 // adds an event handler to the list of the handlers with pending events
120 void AppendPendingEventHandler(wxEvtHandler* toAppend);
121
122 // moves the event handler from the list of the handlers with pending events
123 //to the list of the handlers with _delayed_ pending events
124 void DelayPendingEventHandler(wxEvtHandler* toDelay);
125
126
127 // idle handling
128 // -------------
129
130 // make sure that idle events are sent again
131 virtual void WakeUpIdle();
132
133 // this virtual function is called when the application
134 // becomes idle and normally just sends wxIdleEvent to all interested
135 // parties
136 //
137 // it should return true if more idle events are needed, false if not
138 virtual bool ProcessIdle();
139
140
141 // Yield-related hooks
142 // -------------------
143
144 // process all currently pending events right now
145 //
146 // it is an error to call Yield() recursively unless the value of
147 // onlyIfNeeded is true
148 //
149 // WARNING: this function is dangerous as it can lead to unexpected
150 // reentrancies (i.e. when called from an event handler it
151 // may result in calling the same event handler again), use
152 // with _extreme_ care or, better, don't use at all!
153 bool Yield(bool onlyIfNeeded = false);
154 virtual bool YieldFor(long eventsToProcess) = 0;
155
156 // returns true if the main thread is inside a Yield() call
157 virtual bool IsYielding() const
158 { return m_isInsideYield; }
159
160 // returns true if events of the given event category should be immediately
161 // processed inside a wxApp::Yield() call or rather should be queued for
162 // later processing by the main event loop
163 virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const
164 { return (m_eventsToProcessInsideYield & cat) != 0; }
165
166 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
167
168
169 // active loop
170 // -----------
9af42efd 171
b9f246f7 172 // return currently active (running) event loop, may be NULL
2ddff00c 173 static wxEventLoopBase *GetActive() { return ms_activeLoop; }
3808e191 174
df0e1b64 175 // set currently active (running) event loop
2ddff00c 176 static void SetActive(wxEventLoopBase* loop) { ms_activeLoop = loop; }
df0e1b64 177
b46b1d59 178
3808e191 179protected:
4300caa7
VZ
180 // this function should be called before the event loop terminates, whether
181 // this happens normally (because of Exit() call) or abnormally (because of
182 // an exception thrown from inside the loop)
183 virtual void OnExit() { }
184
b9f246f7 185 // the pointer to currently active loop
2ddff00c 186 static wxEventLoopBase *ms_activeLoop;
22f3361e 187
dde19c21
FM
188 // the array of the handlers with pending events which needs to be processed
189 // inside ProcessPendingEvents()
190 wxEvtHandlerArray m_handlersWithPendingEvents;
191
192 // helper array used by ProcessPendingEvents()
193 wxEvtHandlerArray m_handlersWithPendingDelayedEvents;
194
195#if wxUSE_THREADS
196 // this critical section protects both the lists above
197 wxCriticalSection m_handlersWithPendingEventsLocker;
198#endif
199
200 // Yield() helpers:
201 bool m_isInsideYield;
202 long m_eventsToProcessInsideYield;
203
c0c133e1 204 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
3754265e
VZ
205};
206
b46b1d59 207#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || defined(__UNIX__)
c8026dea
VZ
208
209// this class can be used to implement a standard event loop logic using
210// Pending() and Dispatch()
211//
212// it also handles idle processing automatically
b46b1d59 213class WXDLLIMPEXP_BASE wxEventLoopManual : public wxEventLoopBase
c8026dea
VZ
214{
215public:
216 wxEventLoopManual();
217
218 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
219 // terminating when Exit() is called
220 virtual int Run();
221
222 // sets the "should exit" flag and wakes up the loop so that it terminates
223 // soon
5b87e74a 224 virtual void Exit(int rc = 0);
c8026dea
VZ
225
226protected:
c8026dea
VZ
227 // may be overridden to perform some action at the start of each new event
228 // loop iteration
229 virtual void OnNextIteration() { }
230
231
232 // the loop exit code
233 int m_exitcode;
234
235 // should we exit the loop?
236 bool m_shouldExit;
237};
238
239#endif // platforms using "manual" loop
240
3754265e
VZ
241// we're moving away from old m_impl wxEventLoop model as otherwise the user
242// code doesn't have access to platform-specific wxEventLoop methods and this
243// can sometimes be very useful (e.g. under MSW this is necessary for
244// integration with MFC) but currently this is done for MSW only, other ports
245// should follow a.s.a.p.
4055ed82 246#if defined(__WXPALMOS__)
ffecfa5a
JS
247 #include "wx/palmos/evtloop.h"
248#elif defined(__WXMSW__)
3754265e 249 #include "wx/msw/evtloop.h"
4d90072c 250#elif defined(__WXMAC__)
ef0e9220 251 #include "wx/osx/evtloop.h"
1df4b194
VZ
252#elif defined(__WXCOCOA__)
253 #include "wx/cocoa/evtloop.h"
b3c86150
VS
254#elif defined(__WXDFB__)
255 #include "wx/dfb/evtloop.h"
564c7fc4
VZ
256#elif defined(__WXGTK20__)
257 #include "wx/gtk/evtloop.h"
4d90072c 258#else // other platform
3754265e 259
9c26672d 260#include "wx/stopwatch.h" // for wxMilliClock_t
9af42efd 261
b5dbe15d 262class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
3754265e 263
53a2db12 264class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
3754265e
VZ
265{
266public:
b46b1d59
VZ
267 wxGUIEventLoop() { m_impl = NULL; }
268 virtual ~wxGUIEventLoop();
1a18887b 269
3754265e
VZ
270 virtual int Run();
271 virtual void Exit(int rc = 0);
272 virtual bool Pending() const;
273 virtual bool Dispatch();
9c26672d
VZ
274 virtual int DispatchTimeout(unsigned long timeout)
275 {
276 // TODO: this is, of course, horribly inefficient and a proper wait with
277 // timeout should be implemented for all ports natively...
278 const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
279 for ( ;; )
280 {
281 if ( Pending() )
282 return Dispatch();
283
284 if ( wxGetLocalTimeMillis() >= timeEnd )
285 return -1;
286 }
287 }
b46b1d59 288 virtual void WakeUp() { }
dde19c21 289 virtual bool YieldFor(long eventsToProcess);
3754265e
VZ
290
291protected:
4300caa7
VZ
292 // the pointer to the port specific implementation class
293 wxEventLoopImpl *m_impl;
294
c0c133e1 295 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
4d90072c 296};
3754265e 297
4d90072c 298#endif // platforms
3808e191 299
b46b1d59
VZ
300// also include the header defining wxConsoleEventLoop for Unix systems
301#if defined(__UNIX__)
302 #include "wx/unix/evtloop.h"
303#endif
304
2ddff00c
VZ
305// we use a class rather than a typedef because wxEventLoop is forward-declared
306// in many places
b46b1d59 307#if wxUSE_GUI
2ddff00c
VZ
308 class wxEventLoop : public wxGUIEventLoop { };
309#else // !GUI
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
b46b1d59 321#if wxUSE_GUI
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_