]> git.saurik.com Git - wxWidgets.git/blob - include/wx/evtloop.h
31db6dc9db58c80a644a5a0d7c2823ab2c9d1ec3
[wxWidgets.git] / include / wx / evtloop.h
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>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifndef _WX_EVTLOOP_H_
13 #define _WX_EVTLOOP_H_
14
15 #include "wx/event.h"
16 #include "wx/utils.h"
17 #include "wx/hashset.h"
18
19 // ----------------------------------------------------------------------------
20 // wxEventLoopSource: source of i/o for wxEventLoop
21 // ----------------------------------------------------------------------------
22
23 #define wxTRACE_EVT_SOURCE "EventSource"
24
25 #if defined(__UNIX__) && (wxUSE_CONSOLE_EVENTLOOP || defined(__WXGTK__) || \
26 defined(__WXOSX_COCOA__))
27 #define wxUSE_EVENTLOOP_SOURCE 1
28 #else
29 #define wxUSE_EVENTLOOP_SOURCE 0
30 #endif
31
32 #if wxUSE_EVENTLOOP_SOURCE
33
34 // handler used to process events on event loop sources
35 class WXDLLIMPEXP_BASE wxEventLoopSourceHandler
36 {
37 public:
38 // called when descriptor is available for non-blocking read
39 virtual void OnReadWaiting() = 0;
40
41 // called when descriptor is available for non-blocking write
42 virtual void OnWriteWaiting() = 0;
43
44 // called when there is exception on descriptor
45 virtual void OnExceptionWaiting() = 0;
46
47 // virtual dtor for the base class
48 virtual ~wxEventLoopSourceHandler() { }
49 };
50
51 // those flags describes what events should be reported
52 enum
53 {
54 wxEVENT_SOURCE_INPUT = 0x01,
55 wxEVENT_SOURCE_OUTPUT = 0x02,
56 wxEVENT_SOURCE_EXCEPTION = 0x04,
57 wxEVENT_SOURCE_ALL = wxEVENT_SOURCE_INPUT | wxEVENT_SOURCE_OUTPUT |
58 wxEVENT_SOURCE_EXCEPTION,
59 };
60
61 class wxAbstractEventLoopSource
62 {
63 public:
64 wxAbstractEventLoopSource() :
65 m_handler(NULL), m_flags(-1)
66 {}
67
68 wxAbstractEventLoopSource(wxEventLoopSourceHandler* handler, int flags) :
69 m_handler(handler), m_flags(flags)
70 {}
71
72 virtual ~wxAbstractEventLoopSource() { }
73
74 virtual bool IsOk() const = 0;
75
76 virtual void Invalidate() = 0;
77
78 void SetHandler(wxEventLoopSourceHandler* handler)
79 {
80 m_handler = handler;
81 }
82
83 wxEventLoopSourceHandler* GetHandler() const
84 {
85 return m_handler;
86 }
87
88 void SetFlags(int flags)
89 {
90 m_flags = flags;
91 }
92
93 int GetFlags() const
94 {
95 return m_flags;
96 }
97
98 protected:
99 wxEventLoopSourceHandler* m_handler;
100 int m_flags;
101 };
102
103 // This class is a simple wrapper for OS specific resources than can be a
104 // source of I/O. On Unix,for instance these are file descriptors.
105 //
106 // Instances of this class doesn't take resposibility of any resource you pass
107 // to them, I.E. you have to release them yourself.
108 template<class T>
109 class WXDLLIMPEXP_BASE wxEventLoopSourceBase : public wxAbstractEventLoopSource
110 {
111 public:
112 typedef T Resource;
113
114 // copy ctor
115 wxEventLoopSourceBase(const wxEventLoopSourceBase& source) :
116 wxAbstractEventLoopSource(source.GetHandler(), source.GetFlags()),
117 m_res(source.GetResource())
118 {
119 }
120
121 virtual const T InvalidResource() const
122 {
123 return (T)-1;
124 }
125
126 virtual void Invalidate()
127 {
128 SetResource(InvalidResource());
129 SetHandler(NULL);
130 }
131
132 // sets internal value to res
133 void SetResource(T res)
134 {
135 m_res = res;
136 }
137
138 // returns associated resource
139 T GetResource() const
140 {
141 return m_res;
142 }
143
144 virtual bool IsOk() const
145 {
146 // flags < 0 are invalid and flags == 0 mean monitoring for nothing
147 return m_res != InvalidResource() && m_handler && m_flags >=1;
148 }
149
150 protected:
151 // empty ctor, beacuse we often store event sources as values
152 wxEventLoopSourceBase() :
153 wxAbstractEventLoopSource(),
154 m_res(InvalidResource())
155 {
156 }
157
158 // ctor setting internal value to the os resource res
159 wxEventLoopSourceBase(T res, wxEventLoopSourceHandler* handler,
160 int flags) :
161 wxAbstractEventLoopSource(handler, flags),
162 m_res(res)
163 { }
164
165 T m_res;
166 };
167
168 #if defined(__WXMAC__)
169 class wxMacEventLoopSource : public wxEventLoopSourceBase<CFRunLoopSourceRef>
170 {
171 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
172 int GetFileDescriptor() const
173 {
174 return m_fd;
175 }
176 #endif
177 protected:
178 wxMacEventLoopSource() : wxEventLoopSourceBase<CFRunLoopSourceRef>() { }
179
180 // ctor setting internal value to the os resource res
181 wxMacEventLoopSource(CFRunLoopSourceRef res,
182 wxEventLoopSourceHandler* handler, int flags) :
183 wxEventLoopSourceBase<CFRunLoopSourceRef>(res, handler, flags)
184 {
185 }
186
187 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
188 int m_fd;
189 #endif
190
191 friend class wxGUIEventLoop;
192 };
193 #endif
194
195 #if defined(__UNIX__)
196 class wxUnixEventLoopSource : public wxEventLoopSourceBase<int>
197 {
198 protected:
199 wxUnixEventLoopSource() : wxEventLoopSourceBase<int>() { }
200
201 // ctor setting internal value to the os resource res
202 wxUnixEventLoopSource(int res, wxEventLoopSourceHandler* handler,
203 int flags) :
204 wxEventLoopSourceBase<int>(res, handler, flags)
205 {
206 }
207
208 friend class wxConsoleEventLoop;
209 friend class wxGUIEventLoop;
210 };
211 #endif
212
213 // the list of watched sources
214 WX_DECLARE_HASH_SET(wxAbstractEventLoopSource*, wxPointerHash, wxPointerEqual,
215 wxEventLoopSourceHashSet);
216
217 #endif
218
219
220 /*
221 NOTE ABOUT wxEventLoopBase::YieldFor LOGIC
222 ------------------------------------------
223
224 The YieldFor() function helps to avoid re-entrancy problems and problems
225 caused by out-of-order event processing
226 (see "wxYield-like problems" and "wxProgressDialog+threading BUG" wx-dev threads).
227
228 The logic behind YieldFor() is simple: it analyzes the queue of the native
229 events generated by the underlying GUI toolkit and picks out and processes
230 only those matching the given mask.
231
232 It's important to note that YieldFor() is used to selectively process the
233 events generated by the NATIVE toolkit.
234 Events syntethized by wxWidgets code or by user code are instead selectively
235 processed thanks to the logic built into wxEvtHandler::ProcessPendingEvents().
236 In fact, when wxEvtHandler::ProcessPendingEvents gets called from inside a
237 YieldFor() call, wxEventLoopBase::IsEventAllowedInsideYield is used to decide
238 if the pending events for that event handler can be processed.
239 If all the pending events associated with that event handler result as "not processable",
240 the event handler "delays" itself calling wxEventLoopBase::DelayPendingEventHandler
241 (so it's moved: m_handlersWithPendingEvents => m_handlersWithPendingDelayedEvents).
242 Last, wxEventLoopBase::ProcessPendingEvents() before exiting moves the delayed
243 event handlers back into the list of handlers with pending events
244 (m_handlersWithPendingDelayedEvents => m_handlersWithPendingEvents) so that
245 a later call to ProcessPendingEvents() (possibly outside the YieldFor() call)
246 will process all pending events as usual.
247 */
248
249 // ----------------------------------------------------------------------------
250 // wxEventLoopBase: interface for wxEventLoop
251 // ----------------------------------------------------------------------------
252
253 class WXDLLIMPEXP_BASE wxEventLoopBase
254 {
255 public:
256 // trivial, but needed (because of wxEventLoopBase) ctor
257 wxEventLoopBase();
258
259 // dtor
260 virtual ~wxEventLoopBase() { }
261
262 // use this to check whether the event loop was successfully created before
263 // using it
264 virtual bool IsOk() const { return true; }
265
266 // returns true if this is the main loop
267 bool IsMain() const;
268
269 #if wxUSE_EVENTLOOP_SOURCE
270 virtual wxAbstractEventLoopSource* CreateSource() const = 0;
271
272 virtual wxAbstractEventLoopSource* CreateSource(int WXUNUSED(res),
273 wxEventLoopSourceHandler* WXUNUSED(handler),
274 int WXUNUSED(flags)) const
275 {
276 return NULL;
277 }
278
279 // adds source to be monitored for I/O events specified in flags. Upon an
280 // event the appropriate method of handler will be called. The handler is
281 // owned be the calling client and will not be freed in any case.
282 // Returns true if the source was successfully added, false if it failed
283 // (this may happen for example when this source is already monitored)
284 virtual bool AddSource(wxAbstractEventLoopSource* source)
285 {
286 wxCHECK_MSG( source && source->IsOk(), false, "Invalid source" );
287
288 wxEventLoopSourceHashSet::value_type val(source);
289 if (!m_sourceMap.insert(val).second)
290 {
291 return false;
292 }
293
294 bool ret = DoAddSource(source);
295 if (!ret)
296 {
297 (void) m_sourceMap.erase(source);
298 }
299 return ret;
300 }
301
302 // removes the source from the list of monitored sources.
303 // Returns true if the source was successfully removed, false otherwise
304 virtual bool RemoveSource(wxAbstractEventLoopSource* source)
305 {
306 wxCHECK_MSG( source && source->IsOk(), false, "Invalid source" );
307
308 if (m_sourceMap.find(source) == m_sourceMap.end())
309 {
310 return false;
311 }
312
313 bool ret = DoRemoveSource(source);
314 m_sourceMap.erase(source);
315 return ret;
316 }
317
318 bool RemoveAllSources()
319 {
320 wxEventLoopSourceHashSet::iterator it = m_sourceMap.begin();
321 while ( !m_sourceMap.empty() )
322 {
323 (void) RemoveSource(*it);
324 m_sourceMap.erase(it);
325 it = m_sourceMap.begin();
326 }
327
328 return true;
329 }
330 #endif
331
332 // dispatch&processing
333 // -------------------
334
335 // start the event loop, return the exit code when it is finished
336 virtual int Run() = 0;
337
338 // is this event loop running now?
339 //
340 // notice that even if this event loop hasn't terminated yet but has just
341 // spawned a nested (e.g. modal) event loop, this would return false
342 bool IsRunning() const;
343
344 // exit from the loop with the given exit code
345 virtual void Exit(int rc = 0) = 0;
346
347 // return true if any events are available
348 virtual bool Pending() const = 0;
349
350 // dispatch a single event, return false if we should exit from the loop
351 virtual bool Dispatch() = 0;
352
353 // same as Dispatch() but doesn't wait for longer than the specified (in
354 // ms) timeout, return true if an event was processed, false if we should
355 // exit the loop or -1 if timeout expired
356 virtual int DispatchTimeout(unsigned long timeout) = 0;
357
358 // implement this to wake up the loop: usually done by posting a dummy event
359 // to it (can be called from non main thread)
360 virtual void WakeUp() = 0;
361
362
363 // idle handling
364 // -------------
365
366 // make sure that idle events are sent again
367 virtual void WakeUpIdle();
368
369 // this virtual function is called when the application
370 // becomes idle and by default it forwards to wxApp::ProcessIdle() and
371 // while it can be overridden in a custom event loop, you must call the
372 // base class version to ensure that idle events are still generated
373 //
374 // it should return true if more idle events are needed, false if not
375 virtual bool ProcessIdle();
376
377
378 // Yield-related hooks
379 // -------------------
380
381 // process all currently pending events right now
382 //
383 // it is an error to call Yield() recursively unless the value of
384 // onlyIfNeeded is true
385 //
386 // WARNING: this function is dangerous as it can lead to unexpected
387 // reentrancies (i.e. when called from an event handler it
388 // may result in calling the same event handler again), use
389 // with _extreme_ care or, better, don't use at all!
390 bool Yield(bool onlyIfNeeded = false);
391 virtual bool YieldFor(long eventsToProcess) = 0;
392
393 // returns true if the main thread is inside a Yield() call
394 virtual bool IsYielding() const
395 { return m_isInsideYield; }
396
397 // returns true if events of the given event category should be immediately
398 // processed inside a wxApp::Yield() call or rather should be queued for
399 // later processing by the main event loop
400 virtual bool IsEventAllowedInsideYield(wxEventCategory cat) const
401 { return (m_eventsToProcessInsideYield & cat) != 0; }
402
403 // no SafeYield hooks since it uses wxWindow which is not available when wxUSE_GUI=0
404
405
406 // active loop
407 // -----------
408
409 // return currently active (running) event loop, may be NULL
410 static wxEventLoopBase *GetActive() { return ms_activeLoop; }
411
412 // set currently active (running) event loop
413 static void SetActive(wxEventLoopBase* loop);
414
415
416 protected:
417 #if wxUSE_EVENTLOOP_SOURCE
418 virtual bool DoAddSource(wxAbstractEventLoopSource* source) = 0;
419 virtual bool DoRemoveSource(wxAbstractEventLoopSource* source) = 0;
420
421 wxEventLoopSourceHashSet m_sourceMap;
422 #endif
423
424 // this function should be called before the event loop terminates, whether
425 // this happens normally (because of Exit() call) or abnormally (because of
426 // an exception thrown from inside the loop)
427 virtual void OnExit();
428
429 // the pointer to currently active loop
430 static wxEventLoopBase *ms_activeLoop;
431
432 // YieldFor() helpers:
433 bool m_isInsideYield;
434 long m_eventsToProcessInsideYield;
435
436 wxDECLARE_NO_COPY_CLASS(wxEventLoopBase);
437 };
438
439 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) || defined(__UNIX__)
440
441 // this class can be used to implement a standard event loop logic using
442 // Pending() and Dispatch()
443 //
444 // it also handles idle processing automatically
445 class WXDLLIMPEXP_BASE wxEventLoopManual : public wxEventLoopBase
446 {
447 public:
448 wxEventLoopManual();
449
450 // enters a loop calling OnNextIteration(), Pending() and Dispatch() and
451 // terminating when Exit() is called
452 virtual int Run();
453
454 // sets the "should exit" flag and wakes up the loop so that it terminates
455 // soon
456 virtual void Exit(int rc = 0);
457
458 protected:
459 // may be overridden to perform some action at the start of each new event
460 // loop iteration
461 virtual void OnNextIteration() { }
462
463
464 // the loop exit code
465 int m_exitcode;
466
467 // should we exit the loop?
468 bool m_shouldExit;
469
470 private:
471 // process all already pending events and dispatch a new one (blocking
472 // until it appears in the event queue if necessary)
473 //
474 // returns the return value of Dispatch()
475 bool ProcessEvents();
476
477 wxDECLARE_NO_COPY_CLASS(wxEventLoopManual);
478 };
479
480 #endif // platforms using "manual" loop
481
482 // we're moving away from old m_impl wxEventLoop model as otherwise the user
483 // code doesn't have access to platform-specific wxEventLoop methods and this
484 // can sometimes be very useful (e.g. under MSW this is necessary for
485 // integration with MFC) but currently this is done for MSW only, other ports
486 // should follow a.s.a.p.
487 #if defined(__WXPALMOS__)
488 #include "wx/palmos/evtloop.h"
489 #elif defined(__WXMSW__)
490 #include "wx/msw/evtloop.h"
491 #elif defined(__WXMAC__)
492 #include "wx/osx/evtloop.h"
493 #elif defined(__WXCOCOA__)
494 #include "wx/cocoa/evtloop.h"
495 #elif defined(__WXDFB__)
496 #include "wx/dfb/evtloop.h"
497 #elif defined(__WXGTK__)
498 #include "wx/gtk/evtloop.h"
499 #else // other platform
500
501 #include "wx/stopwatch.h" // for wxMilliClock_t
502
503 class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
504
505 class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
506 {
507 public:
508 wxGUIEventLoop() { m_impl = NULL; }
509 virtual ~wxGUIEventLoop();
510
511 virtual int Run();
512 virtual void Exit(int rc = 0);
513 virtual bool Pending() const;
514 virtual bool Dispatch();
515 virtual int DispatchTimeout(unsigned long timeout)
516 {
517 // TODO: this is, of course, horribly inefficient and a proper wait with
518 // timeout should be implemented for all ports natively...
519 const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
520 for ( ;; )
521 {
522 if ( Pending() )
523 return Dispatch();
524
525 if ( wxGetLocalTimeMillis() >= timeEnd )
526 return -1;
527 }
528 }
529 virtual void WakeUp() { }
530 virtual bool YieldFor(long eventsToProcess);
531
532 protected:
533 // the pointer to the port specific implementation class
534 wxEventLoopImpl *m_impl;
535
536 wxDECLARE_NO_COPY_CLASS(wxGUIEventLoop);
537 };
538
539 #endif // platforms
540
541 // also include the header defining wxConsoleEventLoop for Unix systems
542 #if defined(__UNIX__)
543 #include "wx/unix/evtloop.h"
544 #endif
545
546 // we use a class rather than a typedef because wxEventLoop is forward-declared
547 // in many places
548 #if wxUSE_GUI
549 class wxEventLoop : public wxGUIEventLoop { };
550 #else // !GUI
551 // we can't define wxEventLoop differently in GUI and base libraries so use
552 // a #define to still allow writing wxEventLoop in the user code
553 #if wxUSE_CONSOLE_EVENTLOOP && (defined(__WXMSW__) || defined(__UNIX__))
554 #define wxEventLoop wxConsoleEventLoop
555 #else // we still must define it somehow for the code below...
556 #define wxEventLoop wxEventLoopBase
557 #endif
558 #endif
559
560 inline bool wxEventLoopBase::IsRunning() const { return GetActive() == this; }
561
562 #if wxUSE_GUI
563 // ----------------------------------------------------------------------------
564 // wxModalEventLoop
565 // ----------------------------------------------------------------------------
566
567 // this is a naive generic implementation which uses wxWindowDisabler to
568 // implement modality, we will surely need platform-specific implementations
569 // too, this generic implementation is here only temporarily to see how it
570 // works
571 class WXDLLIMPEXP_CORE wxModalEventLoop : public wxGUIEventLoop
572 {
573 public:
574 wxModalEventLoop(wxWindow *winModal)
575 {
576 m_windowDisabler = new wxWindowDisabler(winModal);
577 }
578
579 protected:
580 virtual void OnExit()
581 {
582 delete m_windowDisabler;
583 m_windowDisabler = NULL;
584
585 wxGUIEventLoop::OnExit();
586 }
587
588 private:
589 wxWindowDisabler *m_windowDisabler;
590 };
591
592 #endif //wxUSE_GUI
593
594 // ----------------------------------------------------------------------------
595 // wxEventLoopActivator: helper class for wxEventLoop implementations
596 // ----------------------------------------------------------------------------
597
598 // this object sets the wxEventLoop given to the ctor as the currently active
599 // one and unsets it in its dtor, this is especially useful in presence of
600 // exceptions but is more tidy even when we don't use them
601 class wxEventLoopActivator
602 {
603 public:
604 wxEventLoopActivator(wxEventLoopBase *evtLoop)
605 {
606 m_evtLoopOld = wxEventLoopBase::GetActive();
607 wxEventLoopBase::SetActive(evtLoop);
608 }
609
610 ~wxEventLoopActivator()
611 {
612 // restore the previously active event loop
613 wxEventLoopBase::SetActive(m_evtLoopOld);
614 }
615
616 private:
617 wxEventLoopBase *m_evtLoopOld;
618 };
619
620 #if wxUSE_CONSOLE_EVENTLOOP
621
622 class wxEventLoopGuarantor
623 {
624 public:
625 wxEventLoopGuarantor()
626 {
627 m_evtLoopNew = NULL;
628 if (!wxEventLoop::GetActive())
629 {
630 m_evtLoopNew = new wxEventLoop;
631 wxEventLoop::SetActive(m_evtLoopNew);
632 }
633 }
634
635 ~wxEventLoopGuarantor()
636 {
637 if (m_evtLoopNew)
638 {
639 wxEventLoop::SetActive(NULL);
640 delete m_evtLoopNew;
641 }
642 }
643
644 private:
645 wxEventLoop *m_evtLoopNew;
646 };
647
648 #endif // wxUSE_CONSOLE_EVENTLOOP
649
650 #endif // _WX_EVTLOOP_H_