- Added wxMemoryInputStream(wxInputStream&) ctor (Stas Sergeev).
- Implemented wxMemoryInputStream::CanRead().
- Implemented wxMemoryFSHandler::FindFirst/Next().
+- Added wxEventLoop::DispatchTimeout().
- Added wxEXEC_BLOCK flag (Hank Schultz).
- Add support for wxStream-derived classes to wxRTTI (Stas Sergeev).
- Added wxStreamBuffer::Truncate() (Stas Sergeev).
virtual bool Pending() const;
virtual bool Dispatch();
+ virtual int DispatchTimeout(unsigned long timeout);
// returns DirectFB event buffer used by wx
static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer();
// using it
virtual bool IsOk() const { return true; }
+
// start the event loop, return the exit code when it is finished
virtual int Run() = 0;
// dispatch a single event, return false if we should exit from the loop
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
static wxEventLoopBase *GetActive() { return ms_activeLoop; }
#include "wx/dfb/evtloop.h"
#else // other platform
+#define wxNEEDS_GENERIC_DISPATCH_TIMEOUT
+
class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
virtual void Exit(int rc = 0);
virtual bool Pending() const;
virtual bool Dispatch();
+ virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp() { }
protected:
// get the next message from queue and return true or return false if we
// got WM_QUIT or an error occurred
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
// override/implement base class virtuals
virtual bool Dispatch();
+ virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
protected:
// override/implement base class virtuals
virtual bool Dispatch();
+ virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
+ // MSW-specific function to process a single message
+ virtual void ProcessMessage(WXMSG *msg);
+
protected:
virtual void OnNextIteration();
};
#ifndef _WX_MAC_CARBON_EVTLOOP_H_
#define _WX_MAC_CARBON_EVTLOOP_H_
+class OpaqueEventRef;
+typedef OpaqueEventRef *EventRef;
+
class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopManual
{
public:
wxGUIEventLoop();
+ // implement/override base class pure virtual
virtual bool Pending() const;
virtual bool Dispatch();
+ virtual int DispatchTimeout(unsigned long timeout);
- // implement base class pure virtual
virtual void WakeUp();
+
private:
+ // dispatch an event and release it
+ void DispatchAndReleaseEvent(EventRef event);
+
double m_sleepTime;
};
virtual void Exit(int rc = 0);
virtual bool Pending() const;
virtual bool Dispatch();
+ virtual int DispatchTimeout(unsigned long timeout);
virtual bool IsRunning() const;
// MSW-specific methods
// implement base class pure virtuals
virtual bool Pending() const;
virtual bool Dispatch();
+ virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp();
virtual bool IsOk() const { return m_dispatcher != NULL; }
*/
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.
}
#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
+
bool wxGUIEventLoop::Dispatch()
{
- wxCHECK_MSG( ms_buffer, false, "invalid event buffer" );
-
// NB: we don't block indefinitely waiting for an event, but instead
// time out after a brief period in order to make sure that
// OnNextIteration() will be called frequently enough
+ //
+ // TODO: remove this hack, instead use CreateFileDescriptor() to properly
+ // multiplex GUI and socket input
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
// events:
wxMutexGuiLeave();
- bool rv = ms_buffer->WaitForEventWithTimeout(0, TIMEOUT);
+ bool rv = ms_buffer->WaitForEventWithTimeout(0, timeout);
// and acquire it back before calling any event handlers:
wxMutexGuiEnter();
}
case DFB_TIMEOUT:
- // timed out, pretend we processed an event so that
- // OnNextIteration is called
- break;
+ return -1;
default:
// don't terminate the loop due to errors (they were reported
}
}
- return true;
+ return 1;
}
void wxGUIEventLoop::WakeUp()
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
#if wxUSE_GUI
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()
{
#if wxUSE_THREADS
#endif
}
-bool wxConsoleEventLoop::Dispatch()
+void wxConsoleEventLoop::ProcessMessage(WXMSG *msg)
{
- MSG msg;
- if ( !GetNextMessage(&msg) )
- return false;
-
- if ( msg.message == WM_TIMER )
+ if ( msg->message == WM_TIMER )
{
- TIMERPROC proc = (TIMERPROC)msg.lParam;
+ TIMERPROC proc = (TIMERPROC)msg->lParam;
if ( proc )
- (*proc)(NULL, 0, msg.wParam, 0);
+ (*proc)(NULL, 0, msg->wParam, 0);
}
else
{
- ::DispatchMessage(&msg);
+ ::DispatchMessage(msg);
}
+}
+
+bool wxConsoleEventLoop::Dispatch()
+{
+ MSG msg;
+ if ( !GetNextMessage(&msg) )
+ return false;
+
+ ProcessMessage(&msg);
+
+ return !m_shouldExit;
+}
+
+int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout)
+{
+ MSG msg;
+ int rc = GetNextMessageTimeout(&msg, timeout);
+ if ( rc != 1 )
+ return rc;
+
+ ProcessMessage(&msg);
return !m_shouldExit;
}
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
{
EventRef theEvent;
break;
default:
- if ( wxTheApp )
- wxTheApp->MacSetCurrentEvent( theEvent, NULL );
-
- OSStatus status = SendEventToEventTarget(theEvent, GetEventDispatcherTarget());
- if (status == eventNotHandledErr && wxTheApp)
- wxTheApp->MacHandleUnhandledEvent(theEvent);
-
- ReleaseEvent( theEvent );
+ DispatchAndReleaseEvent(theEvent);
m_sleepTime = kEventDurationNoWait ;
break;
}
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;
+ }
+}
+
return false;
}
+int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
+{
+ return -1;
+}
+
void wxGUIEventLoop::WakeUp()
{
return;
bool wxConsoleEventLoop::Dispatch()
{
- // calculate the timeout until the next timer expiration
- int timeout;
+ DispatchTimeout(wxFDIODispatcher::TIMEOUT_INFINITE);
+ return true;
+}
+
+int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout)
+{
#if wxUSE_TIMER
+ // check if we need to decrease the timeout to account for a timer
wxUsecClock_t nextTimer;
if ( wxTimerScheduler::Get().GetNext(&nextTimer) )
{
- // timeout is in ms
- timeout = (nextTimer / 1000).ToLong();
+ unsigned long timeUntilNextTimer = wxMilliClockToLong(nextTimer / 1000);
+ if ( timeUntilNextTimer < timeout )
+ timeout = timeUntilNextTimer;
}
- else // no timers, we can block forever
#endif // wxUSE_TIMER
- {
- timeout = wxFDIODispatcher::TIMEOUT_INFINITE;
- }
- m_dispatcher->Dispatch(timeout);
+ bool hadEvent = m_dispatcher->Dispatch(timeout);
#if wxUSE_TIMER
- wxTimerScheduler::Get().NotifyExpired();
-#endif
+ if ( wxTimerScheduler::Get().NotifyExpired() )
+ hadEvent = true;
+#endif // wxUSE_TIMER
wxTheApp->ProcessPendingEvents();
- return true;
+
+ return hadEvent ? 1 : -1;
}
void wxConsoleEventLoop::WakeUp()