added wxEventLoop::DispatchTimeout()

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57571 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-12-26 22:28:34 +00:00
parent aa8cbe0b64
commit 9af42efda6
14 changed files with 216 additions and 38 deletions

View File

@@ -291,6 +291,7 @@ All:
- Added wxMemoryInputStream(wxInputStream&) ctor (Stas Sergeev). - Added wxMemoryInputStream(wxInputStream&) ctor (Stas Sergeev).
- Implemented wxMemoryInputStream::CanRead(). - Implemented wxMemoryInputStream::CanRead().
- Implemented wxMemoryFSHandler::FindFirst/Next(). - Implemented wxMemoryFSHandler::FindFirst/Next().
- Added wxEventLoop::DispatchTimeout().
- Added wxEXEC_BLOCK flag (Hank Schultz). - Added wxEXEC_BLOCK flag (Hank Schultz).
- Add support for wxStream-derived classes to wxRTTI (Stas Sergeev). - Add support for wxStream-derived classes to wxRTTI (Stas Sergeev).
- Added wxStreamBuffer::Truncate() (Stas Sergeev). - Added wxStreamBuffer::Truncate() (Stas Sergeev).

View File

@@ -27,6 +27,7 @@ public:
virtual bool Pending() const; virtual bool Pending() const;
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
// returns DirectFB event buffer used by wx // returns DirectFB event buffer used by wx
static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer(); static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer();

View File

@@ -31,6 +31,7 @@ public:
// using it // using it
virtual bool IsOk() const { return true; } virtual bool IsOk() const { return true; }
// start the event loop, return the exit code when it is finished // start the event loop, return the exit code when it is finished
virtual int Run() = 0; virtual int Run() = 0;
@@ -43,6 +44,12 @@ public:
// dispatch a single event, return false if we should exit from the loop // dispatch a single event, return false if we should exit from the loop
virtual bool Dispatch() = 0; virtual bool Dispatch() = 0;
// same as Dispatch() but doesn't wait for longer than the specified (in
// ms) timeout, return true if an event was processed, false if we should
// exit the loop or -1 if timeout expired
virtual int DispatchTimeout(unsigned long timeout) = 0;
// return currently active (running) event loop, may be NULL // return currently active (running) event loop, may be NULL
static wxEventLoopBase *GetActive() { return ms_activeLoop; } static wxEventLoopBase *GetActive() { return ms_activeLoop; }
@@ -121,6 +128,8 @@ protected:
#include "wx/dfb/evtloop.h" #include "wx/dfb/evtloop.h"
#else // other platform #else // other platform
#define wxNEEDS_GENERIC_DISPATCH_TIMEOUT
class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl; class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
@@ -133,6 +142,7 @@ public:
virtual void Exit(int rc = 0); virtual void Exit(int rc = 0);
virtual bool Pending() const; virtual bool Pending() const;
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp() { } virtual void WakeUp() { }
protected: protected:

View File

@@ -32,6 +32,10 @@ protected:
// get the next message from queue and return true or return false if we // get the next message from queue and return true or return false if we
// got WM_QUIT or an error occurred // got WM_QUIT or an error occurred
bool GetNextMessage(WXMSG *msg); bool GetNextMessage(WXMSG *msg);
// same as above but with a timeout and return value can be -1 meaning that
// time out expired in addition to
int GetNextMessageTimeout(WXMSG *msg, unsigned long timeout);
}; };
#if wxUSE_GUI #if wxUSE_GUI
@@ -66,6 +70,7 @@ public:
// override/implement base class virtuals // override/implement base class virtuals
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp(); virtual void WakeUp();
protected: protected:
@@ -92,8 +97,12 @@ public:
// override/implement base class virtuals // override/implement base class virtuals
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp(); virtual void WakeUp();
// MSW-specific function to process a single message
virtual void ProcessMessage(WXMSG *msg);
protected: protected:
virtual void OnNextIteration(); virtual void OnNextIteration();
}; };

View File

@@ -12,17 +12,25 @@
#ifndef _WX_MAC_CARBON_EVTLOOP_H_ #ifndef _WX_MAC_CARBON_EVTLOOP_H_
#define _WX_MAC_CARBON_EVTLOOP_H_ #define _WX_MAC_CARBON_EVTLOOP_H_
class OpaqueEventRef;
typedef OpaqueEventRef *EventRef;
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopManual class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopManual
{ {
public: public:
wxGUIEventLoop(); wxGUIEventLoop();
// implement/override base class pure virtual
virtual bool Pending() const; virtual bool Pending() const;
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
// implement base class pure virtual
virtual void WakeUp(); virtual void WakeUp();
private: private:
// dispatch an event and release it
void DispatchAndReleaseEvent(EventRef event);
double m_sleepTime; double m_sleepTime;
}; };

View File

@@ -26,6 +26,7 @@ public:
virtual void Exit(int rc = 0); virtual void Exit(int rc = 0);
virtual bool Pending() const; virtual bool Pending() const;
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual bool IsRunning() const; virtual bool IsRunning() const;
// MSW-specific methods // MSW-specific methods

View File

@@ -29,6 +29,7 @@ public:
// implement base class pure virtuals // implement base class pure virtuals
virtual bool Pending() const; virtual bool Pending() const;
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp(); virtual void WakeUp();
virtual bool IsOk() const { return m_dispatcher != NULL; } virtual bool IsOk() const { return m_dispatcher != NULL; }

View File

@@ -82,6 +82,24 @@ public:
*/ */
virtual bool Dispatch() = 0; virtual bool Dispatch() = 0;
/**
Dispatch an event but not wait longer than the specified timeout for
it.
If an event is received before the specified @a timeout expires, it is
processed and the function returns 1 normally or 0 if the event loop
should quite. Otherwise, i.e. if the timeout expires, the functions
returns -1 without processing any events.
@param timeout
The maximal time to wait for the events in milliseconds.
@return
1 if an event was processed, 0 if the event loop should quit or -1
if the timeout expired.
*/
virtual int DispatchTimeout(unsigned long timeout) = 0;
/** /**
Return true if this event loop is currently running. Return true if this event loop is currently running.

View File

@@ -153,3 +153,23 @@ void wxEventLoopManual::Exit(int rc)
} }
#endif // __WXMSW__ || __WXMAC__ || __WXDFB__ #endif // __WXMSW__ || __WXMAC__ || __WXDFB__
#ifdef wxNEEDS_GENERIC_DISPATCH_TIMEOUT
int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
{
// TODO: this is, of course, horribly inefficient and a proper wait with
// timeout should be implemented for all ports natively...
const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
for ( ;; )
{
if ( Pending() )
return Dispatch();
if ( wxGetLocalTimeMillis() >= timeEnd )
return -1;
}
}
#endif // wxNEEDS_GENERIC_DISPATCH_TIMEOUT

View File

@@ -83,18 +83,28 @@ bool wxGUIEventLoop::Pending() const
bool wxGUIEventLoop::Dispatch() bool wxGUIEventLoop::Dispatch()
{ {
wxCHECK_MSG( ms_buffer, false, "invalid event buffer" );
// NB: we don't block indefinitely waiting for an event, but instead // NB: we don't block indefinitely waiting for an event, but instead
// time out after a brief period in order to make sure that // time out after a brief period in order to make sure that
// OnNextIteration() will be called frequently enough // OnNextIteration() will be called frequently enough
//
// TODO: remove this hack, instead use CreateFileDescriptor() to properly
// multiplex GUI and socket input
const int TIMEOUT = 100; const int TIMEOUT = 100;
// treat time out (-1 return value) as normal successful return so that
// OnNextIteration() is called
return !!DispatchTimeout(TIMEOUT);
}
int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
{
wxCHECK_MSG( ms_buffer, 0, "invalid event buffer" );
// release the GUI mutex so that other threads have a chance to post // release the GUI mutex so that other threads have a chance to post
// events: // events:
wxMutexGuiLeave(); wxMutexGuiLeave();
bool rv = ms_buffer->WaitForEventWithTimeout(0, TIMEOUT); bool rv = ms_buffer->WaitForEventWithTimeout(0, timeout);
// and acquire it back before calling any event handlers: // and acquire it back before calling any event handlers:
wxMutexGuiEnter(); wxMutexGuiEnter();
@@ -112,9 +122,7 @@ bool wxGUIEventLoop::Dispatch()
} }
case DFB_TIMEOUT: case DFB_TIMEOUT:
// timed out, pretend we processed an event so that return -1;
// OnNextIteration is called
break;
default: default:
// don't terminate the loop due to errors (they were reported // don't terminate the loop due to errors (they were reported
@@ -123,7 +131,7 @@ bool wxGUIEventLoop::Dispatch()
} }
} }
return true; return 1;
} }
void wxGUIEventLoop::WakeUp() void wxGUIEventLoop::WakeUp()

View File

@@ -99,6 +99,41 @@ bool wxMSWEventLoopBase::GetNextMessage(WXMSG* msg)
return true; return true;
} }
int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
{
// MsgWaitForMultipleObjects() won't notice any input which was already
// examined (e.g. using PeekMessage()) but not yet removed from the queue
// so we need to remove any immediately messages manually
//
// NB: using MsgWaitForMultipleObjectsEx() could simplify the code here but
// it is not available in very old Windows versions
if ( !::PeekMessage(msg, 0, 0, 0, PM_REMOVE) )
{
// we use this function just in order to not block longer than the
// given timeout, so we don't pass any handles to it at all
if ( ::MsgWaitForMultipleObjects
(
0, NULL,
FALSE,
timeout,
QS_ALLINPUT
) == WAIT_TIMEOUT )
{
return -1;
}
if ( !::PeekMessage(msg, 0, 0, 0, PM_REMOVE) )
{
wxFAIL_MSG( _T("PeekMessage() should have succeeded") );
return -1;
}
}
return msg->message != WM_QUIT;
}
#endif // wxUSE_BASE #endif // wxUSE_BASE
#if wxUSE_GUI #if wxUSE_GUI
@@ -289,6 +324,18 @@ bool wxGUIEventLoop::Dispatch()
return true; return true;
} }
int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
{
MSG msg;
int rc = GetNextMessageTimeout(&msg, timeout);
if ( rc != 1 )
return rc;
ProcessMessage(&msg);
return 1;
}
void wxGUIEventLoop::OnNextIteration() void wxGUIEventLoop::OnNextIteration()
{ {
#if wxUSE_THREADS #if wxUSE_THREADS
@@ -318,22 +365,39 @@ void wxConsoleEventLoop::WakeUp()
#endif #endif
} }
void wxConsoleEventLoop::ProcessMessage(WXMSG *msg)
{
if ( msg->message == WM_TIMER )
{
TIMERPROC proc = (TIMERPROC)msg->lParam;
if ( proc )
(*proc)(NULL, 0, msg->wParam, 0);
}
else
{
::DispatchMessage(msg);
}
}
bool wxConsoleEventLoop::Dispatch() bool wxConsoleEventLoop::Dispatch()
{ {
MSG msg; MSG msg;
if ( !GetNextMessage(&msg) ) if ( !GetNextMessage(&msg) )
return false; return false;
if ( msg.message == WM_TIMER ) ProcessMessage(&msg);
{
TIMERPROC proc = (TIMERPROC)msg.lParam; return !m_shouldExit;
if ( proc ) }
(*proc)(NULL, 0, msg.wParam, 0);
} int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout)
else {
{ MSG msg;
::DispatchMessage(&msg); int rc = GetNextMessageTimeout(&msg, timeout);
} if ( rc != 1 )
return rc;
ProcessMessage(&msg);
return !m_shouldExit; return !m_shouldExit;
} }

View File

@@ -48,6 +48,18 @@ void wxGUIEventLoop::WakeUp()
wxMacWakeUp(); wxMacWakeUp();
} }
void wxGUIEventLoop::DispatchAndReleaseEvent(EventRef theEvent)
{
if ( wxTheApp )
wxTheApp->MacSetCurrentEvent( theEvent, NULL );
OSStatus status = SendEventToEventTarget(theEvent, GetEventDispatcherTarget());
if (status == eventNotHandledErr && wxTheApp)
wxTheApp->MacHandleUnhandledEvent(theEvent);
ReleaseEvent( theEvent );
}
bool wxGUIEventLoop::Pending() const bool wxGUIEventLoop::Pending() const
{ {
EventRef theEvent; EventRef theEvent;
@@ -95,17 +107,33 @@ bool wxGUIEventLoop::Dispatch()
break; break;
default: default:
if ( wxTheApp ) DispatchAndReleaseEvent(theEvent);
wxTheApp->MacSetCurrentEvent( theEvent, NULL );
OSStatus status = SendEventToEventTarget(theEvent, GetEventDispatcherTarget());
if (status == eventNotHandledErr && wxTheApp)
wxTheApp->MacHandleUnhandledEvent(theEvent);
ReleaseEvent( theEvent );
m_sleepTime = kEventDurationNoWait ; m_sleepTime = kEventDurationNoWait ;
break; break;
} }
return true; return true;
} }
int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
{
EventRef event;
OSStatus status = ReceiveNextEvent(0, NULL, timeout/1000, true, &event);
switch ( status )
{
default:
wxFAIL_MSG( "unexpected ReceiveNextEvent() error" );
// fall through
case eventLoopTimedOutErr:
return -1;
case eventLoopQuitErr:
return 0;
case noErr:
DispatchAndReleaseEvent(event);
return 1;
}
}

View File

@@ -135,6 +135,11 @@ bool wxGUIEventLoop::Dispatch()
return false; return false;
} }
int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
{
return -1;
}
void wxGUIEventLoop::WakeUp() void wxGUIEventLoop::WakeUp()
{ {
return; return;

View File

@@ -149,30 +149,34 @@ bool wxConsoleEventLoop::Pending() const
bool wxConsoleEventLoop::Dispatch() bool wxConsoleEventLoop::Dispatch()
{ {
// calculate the timeout until the next timer expiration DispatchTimeout(wxFDIODispatcher::TIMEOUT_INFINITE);
int timeout;
return true;
}
int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout)
{
#if wxUSE_TIMER #if wxUSE_TIMER
// check if we need to decrease the timeout to account for a timer
wxUsecClock_t nextTimer; wxUsecClock_t nextTimer;
if ( wxTimerScheduler::Get().GetNext(&nextTimer) ) if ( wxTimerScheduler::Get().GetNext(&nextTimer) )
{ {
// timeout is in ms unsigned long timeUntilNextTimer = wxMilliClockToLong(nextTimer / 1000);
timeout = (nextTimer / 1000).ToLong(); if ( timeUntilNextTimer < timeout )
timeout = timeUntilNextTimer;
} }
else // no timers, we can block forever
#endif // wxUSE_TIMER #endif // wxUSE_TIMER
{
timeout = wxFDIODispatcher::TIMEOUT_INFINITE;
}
m_dispatcher->Dispatch(timeout); bool hadEvent = m_dispatcher->Dispatch(timeout);
#if wxUSE_TIMER #if wxUSE_TIMER
wxTimerScheduler::Get().NotifyExpired(); if ( wxTimerScheduler::Get().NotifyExpired() )
#endif hadEvent = true;
#endif // wxUSE_TIMER
wxTheApp->ProcessPendingEvents(); wxTheApp->ProcessPendingEvents();
return true;
return hadEvent ? 1 : -1;
} }
void wxConsoleEventLoop::WakeUp() void wxConsoleEventLoop::WakeUp()