]> git.saurik.com Git - wxWidgets.git/blame - include/wx/evtloop.h
wxOSX build fix after wxTextEntry::GetValue() renaming to DoGetValue()
[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
99 // pending events
100 // --------------
101
102 // process all events in the wxHandlersWithPendingEvents list -- it is necessary
103 // to call this function to process posted events. This happens during each
104 // event loop iteration in GUI mode but if there is no main loop, it may be
105 // also called directly.
106 virtual void ProcessPendingEvents();
107
108 // check if there are pending events on global pending event list
109 bool HasPendingEvents() const;
110
111 // temporary suspends processing of the pending events
112 void SuspendProcessingOfPendingEvents();
113
114 // resume processing of the pending events previously stopped because of a
115 // call to SuspendProcessingOfPendingEvents()
116 void ResumeProcessingOfPendingEvents();
117
118 // called by ~wxEvtHandler to (eventually) remove the handler from the list of
119 // the handlers with pending events
120 void RemovePendingEventHandler(wxEvtHandler* toRemove);
121
122 // adds an event handler to the list of the handlers with pending events
123 void AppendPendingEventHandler(wxEvtHandler* toAppend);
124
125 // moves the event handler from the list of the handlers with pending events
126 //to the list of the handlers with _delayed_ pending events
127 void DelayPendingEventHandler(wxEvtHandler* toDelay);
128
129
130 // idle handling
131 // -------------
132
133 // make sure that idle events are sent again
134 virtual void WakeUpIdle();
135
136 // this virtual function is called when the application
137 // becomes idle and normally just sends wxIdleEvent to all interested
138 // parties
139 //
140 // it should return true if more idle events are needed, false if not
141 virtual bool ProcessIdle();
142
143
144 // Yield-related hooks
145 // -------------------
146
147 // process all currently pending events right now
148 //
149 // it is an error to call Yield() recursively unless the value of
150 // onlyIfNeeded is true
151 //
152 // WARNING: this function is dangerous as it can lead to unexpected
153 // reentrancies (i.e. when called from an event handler it
154 // may result in calling the same event handler again), use
155 // with _extreme_ care or, better, don't use at all!
156 bool Yield(bool onlyIfNeeded = false);
157 virtual bool YieldFor(long eventsToProcess) = 0;
158
159 // returns true if the main thread is inside a Yield() call
160 virtual bool IsYielding() const
161 { return m_isInsideYield; }
162
163 // returns true if events of the given event category should be immediately
164 // processed inside a wxApp::Yield() call or rather should be queued for
165 // later processing by the main event loop
166 virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const
167 { return (m_eventsToProcessInsideYield & cat) != 0; }
168
169 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
170
171
172 // active loop
173 // -----------
9af42efd 174
b9f246f7 175 // return currently active (running) event loop, may be NULL
2ddff00c 176 static wxEventLoopBase *GetActive() { return ms_activeLoop; }
3808e191 177
df0e1b64 178 // set currently active (running) event loop
ec38d07d 179 static void SetActive(wxEventLoopBase* loop);
df0e1b64 180
b46b1d59 181
3808e191 182protected:
4300caa7
VZ
183 // this function should be called before the event loop terminates, whether
184 // this happens normally (because of Exit() call) or abnormally (because of
185 // an exception thrown from inside the loop)
ec38d07d 186 virtual void OnExit();
4300caa7 187
b9f246f7 188 // the pointer to currently active loop
2ddff00c 189 static wxEventLoopBase *ms_activeLoop;
22f3361e 190
dde19c21
FM
191 // the array of the handlers with pending events which needs to be processed
192 // inside ProcessPendingEvents()
193 wxEvtHandlerArray m_handlersWithPendingEvents;
194
195 // helper array used by ProcessPendingEvents()
196 wxEvtHandlerArray m_handlersWithPendingDelayedEvents;
197
198#if wxUSE_THREADS
199 // this critical section protects both the lists above
200 wxCriticalSection m_handlersWithPendingEventsLocker;
201#endif
202
203 // Yield() helpers:
204 bool m_isInsideYield;
205 long m_eventsToProcessInsideYield;
206
c0c133e1 207 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
3754265e
VZ
208};
209
b46b1d59 210#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || defined(__UNIX__)
c8026dea
VZ
211
212// this class can be used to implement a standard event loop logic using
213// Pending() and Dispatch()
214//
215// it also handles idle processing automatically
b46b1d59 216class WXDLLIMPEXP_BASE wxEventLoopManual : public wxEventLoopBase
c8026dea
VZ
217{
218public:
219 wxEventLoopManual();
220
221 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
222 // terminating when Exit() is called
223 virtual int Run();
224
225 // sets the "should exit" flag and wakes up the loop so that it terminates
226 // soon
5b87e74a 227 virtual void Exit(int rc = 0);
c8026dea
VZ
228
229protected:
c8026dea
VZ
230 // may be overridden to perform some action at the start of each new event
231 // loop iteration
232 virtual void OnNextIteration() { }
233
234
235 // the loop exit code
236 int m_exitcode;
237
238 // should we exit the loop?
239 bool m_shouldExit;
240};
241
242#endif // platforms using "manual" loop
243
3754265e
VZ
244// we're moving away from old m_impl wxEventLoop model as otherwise the user
245// code doesn't have access to platform-specific wxEventLoop methods and this
246// can sometimes be very useful (e.g. under MSW this is necessary for
247// integration with MFC) but currently this is done for MSW only, other ports
248// should follow a.s.a.p.
4055ed82 249#if defined(__WXPALMOS__)
ffecfa5a
JS
250 #include "wx/palmos/evtloop.h"
251#elif defined(__WXMSW__)
3754265e 252 #include "wx/msw/evtloop.h"
4d90072c 253#elif defined(__WXMAC__)
ef0e9220 254 #include "wx/osx/evtloop.h"
1df4b194
VZ
255#elif defined(__WXCOCOA__)
256 #include "wx/cocoa/evtloop.h"
b3c86150
VS
257#elif defined(__WXDFB__)
258 #include "wx/dfb/evtloop.h"
564c7fc4
VZ
259#elif defined(__WXGTK20__)
260 #include "wx/gtk/evtloop.h"
4d90072c 261#else // other platform
3754265e 262
9c26672d 263#include "wx/stopwatch.h" // for wxMilliClock_t
9af42efd 264
b5dbe15d 265class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
3754265e 266
53a2db12 267class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
3754265e
VZ
268{
269public:
b46b1d59
VZ
270 wxGUIEventLoop() { m_impl = NULL; }
271 virtual ~wxGUIEventLoop();
1a18887b 272
3754265e
VZ
273 virtual int Run();
274 virtual void Exit(int rc = 0);
275 virtual bool Pending() const;
276 virtual bool Dispatch();
9c26672d
VZ
277 virtual int DispatchTimeout(unsigned long timeout)
278 {
279 // TODO: this is, of course, horribly inefficient and a proper wait with
280 // timeout should be implemented for all ports natively...
281 const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
282 for ( ;; )
283 {
284 if ( Pending() )
285 return Dispatch();
286
287 if ( wxGetLocalTimeMillis() >= timeEnd )
288 return -1;
289 }
290 }
b46b1d59 291 virtual void WakeUp() { }
dde19c21 292 virtual bool YieldFor(long eventsToProcess);
3754265e
VZ
293
294protected:
4300caa7
VZ
295 // the pointer to the port specific implementation class
296 wxEventLoopImpl *m_impl;
297
c0c133e1 298 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
4d90072c 299};
3754265e 300
4d90072c 301#endif // platforms
3808e191 302
b46b1d59
VZ
303// also include the header defining wxConsoleEventLoop for Unix systems
304#if defined(__UNIX__)
305 #include "wx/unix/evtloop.h"
306#endif
307
2ddff00c
VZ
308// we use a class rather than a typedef because wxEventLoop is forward-declared
309// in many places
b46b1d59 310#if wxUSE_GUI
2ddff00c
VZ
311 class wxEventLoop : public wxGUIEventLoop { };
312#else // !GUI
313 // we can't define wxEventLoop differently in GUI and base libraries so use
314 // a #define to still allow writing wxEventLoop in the user code
1a7cfc94 315 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WXMSW__) || defined(__UNIX__))
2ddff00c
VZ
316 #define wxEventLoop wxConsoleEventLoop
317 #else // we still must define it somehow for the code below...
318 #define wxEventLoop wxEventLoopBase
319 #endif
b46b1d59
VZ
320#endif
321
77fb1a02
VZ
322inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
323
b46b1d59 324#if wxUSE_GUI
4300caa7
VZ
325// ----------------------------------------------------------------------------
326// wxModalEventLoop
327// ----------------------------------------------------------------------------
328
329// this is a naive generic implementation which uses wxWindowDisabler to
330// implement modality, we will surely need platform-specific implementations
331// too, this generic implementation is here only temporarily to see how it
332// works
53a2db12 333class WXDLLIMPEXP_CORE wxModalEventLoop : public wxGUIEventLoop
4300caa7
VZ
334{
335public:
336 wxModalEventLoop(wxWindow *winModal)
337 {
338 m_windowDisabler = new wxWindowDisabler(winModal);
339 }
340
341protected:
342 virtual void OnExit()
343 {
344 delete m_windowDisabler;
345 m_windowDisabler = NULL;
346
b46b1d59 347 wxGUIEventLoop::OnExit();
4300caa7
VZ
348 }
349
350private:
351 wxWindowDisabler *m_windowDisabler;
352};
353
b46b1d59
VZ
354#endif //wxUSE_GUI
355
77fb1a02
VZ
356// ----------------------------------------------------------------------------
357// wxEventLoopActivator: helper class for wxEventLoop implementations
358// ----------------------------------------------------------------------------
359
360// this object sets the wxEventLoop given to the ctor as the currently active
361// one and unsets it in its dtor, this is especially useful in presence of
362// exceptions but is more tidy even when we don't use them
363class wxEventLoopActivator
364{
365public:
b46b1d59 366 wxEventLoopActivator(wxEventLoopBase *evtLoop)
77fb1a02 367 {
b46b1d59 368 m_evtLoopOld = wxEventLoopBase::GetActive();
2ddff00c 369 wxEventLoopBase::SetActive(evtLoop);
77fb1a02
VZ
370 }
371
372 ~wxEventLoopActivator()
373 {
374 // restore the previously active event loop
b46b1d59 375 wxEventLoopBase::SetActive(m_evtLoopOld);
77fb1a02
VZ
376 }
377
378private:
2ddff00c 379 wxEventLoopBase *m_evtLoopOld;
77fb1a02
VZ
380};
381
1a7cfc94
VZ
382#if wxUSE_CONSOLE_EVENTLOOP
383
f212e222
SN
384class wxEventLoopGuarantor
385{
386public:
387 wxEventLoopGuarantor()
388 {
389 m_evtLoopNew = NULL;
390 if (!wxEventLoop::GetActive())
391 {
392 m_evtLoopNew = new wxEventLoop;
393 wxEventLoop::SetActive(m_evtLoopNew);
394 }
395 }
396
397 ~wxEventLoopGuarantor()
398 {
399 if (m_evtLoopNew)
400 {
401 wxEventLoop::SetActive(NULL);
402 delete m_evtLoopNew;
403 }
404 }
405
406private:
407 wxEventLoop *m_evtLoopNew;
408};
409
1a7cfc94
VZ
410#endif // wxUSE_CONSOLE_EVENTLOOP
411
3808e191 412#endif // _WX_EVTLOOP_H_