]> git.saurik.com Git - wxWidgets.git/commitdiff
added wxEventLoop::DispatchTimeout()
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 26 Dec 2008 22:28:34 +0000 (22:28 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 26 Dec 2008 22:28:34 +0000 (22:28 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57571 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

14 files changed:
docs/changes.txt
include/wx/dfb/evtloop.h
include/wx/evtloop.h
include/wx/msw/evtloop.h
include/wx/osx/carbon/evtloop.h
include/wx/palmos/evtloop.h
include/wx/unix/evtloop.h
interface/wx/evtloop.h
src/common/evtloopcmn.cpp
src/dfb/evtloop.cpp
src/msw/evtloop.cpp
src/osx/carbon/evtloop.cpp
src/palmos/evtloop.cpp
src/unix/evtloopunix.cpp

index f08a7c08c3ae56cba3ba4f55638a0acf367634de..0941ac08bd0ccef9ff80beb549cafab24b89dd57 100644 (file)
@@ -291,6 +291,7 @@ All:
 - 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).
index 80c0b1f069972b8ec5e00caef0d2bce2d0499184..4c3380819a62f1253346b2558a144bfbe780d567 100644 (file)
@@ -27,6 +27,7 @@ public:
 
     virtual bool Pending() const;
     virtual bool Dispatch();
+    virtual int DispatchTimeout(unsigned long timeout);
 
     // returns DirectFB event buffer used by wx
     static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer();
index bb22bb84db56f5460ee59fb8bece0aeeddc4bab5..5d78a3bf56f983357128a998eddb0b32816b07c1 100644 (file)
@@ -31,6 +31,7 @@ public:
     // using it
     virtual bool IsOk() const { return true; }
 
+
     // start the event loop, return the exit code when it is finished
     virtual int Run() = 0;
 
@@ -43,6 +44,12 @@ public:
     // 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; }
 
@@ -121,6 +128,8 @@ protected:
     #include "wx/dfb/evtloop.h"
 #else // other platform
 
+#define wxNEEDS_GENERIC_DISPATCH_TIMEOUT
+
 class WXDLLIMPEXP_FWD_CORE wxEventLoopImpl;
 
 class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
@@ -133,6 +142,7 @@ public:
     virtual void Exit(int rc = 0);
     virtual bool Pending() const;
     virtual bool Dispatch();
+    virtual int DispatchTimeout(unsigned long timeout);
     virtual void WakeUp() { }
 
 protected:
index fd548b87f25aa3bf6fada941a6e954a182010e58..88ab13492bfe1d0b71b0560908344534ca8a359e 100644 (file)
@@ -32,6 +32,10 @@ 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
@@ -66,6 +70,7 @@ public:
 
     // override/implement base class virtuals
     virtual bool Dispatch();
+    virtual int DispatchTimeout(unsigned long timeout);
     virtual void WakeUp();
 
 protected:
@@ -92,8 +97,12 @@ public:
 
     // 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();
 };
index 60f5704574a06b7a9057ff99f51f689f5b1356c8..b55112994f35784a4d4a09d85033b8d6b6bc3e8c 100644 (file)
 #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;
 };
 
index 6cd10d6245b5aee11ae5ced1f978e51c8a40118b..36341946e8ab356be34ddcfbcbda78bea77f46d0 100644 (file)
@@ -26,6 +26,7 @@ public:
     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
index 3f5b54913c1d8cc3bf4580188fb33054b4fd5e68..ddb101516f9deea85b8007018d55af6ea0930a25 100644 (file)
@@ -29,6 +29,7 @@ public:
     // 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; }
 
index d4a7966a953bef405989b9f8e61dabfb4a608e07..be246731b55a19210606cadd71aa6ce426d85dfd 100644 (file)
@@ -82,6 +82,24 @@ public:
      */
     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.
 
index 3db4ddacf6bc0b21c466a72ca6854ccf1717ef71..997718b44aedca26bf9b428d18a31e39f8084a5d 100644 (file)
@@ -153,3 +153,23 @@ void wxEventLoopManual::Exit(int rc)
 }
 
 #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
+
index 6c6bef402dda24966606669626cb08e6b594eae1..7f7807ac72fefe330aedb15e760d194a92042859 100644 (file)
@@ -83,18 +83,28 @@ bool wxGUIEventLoop::Pending() const
 
 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();
@@ -112,9 +122,7 @@ bool wxGUIEventLoop::Dispatch()
             }
 
             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
@@ -123,7 +131,7 @@ bool wxGUIEventLoop::Dispatch()
         }
     }
 
-    return true;
+    return 1;
 }
 
 void wxGUIEventLoop::WakeUp()
index 601b8b870b2405eecc7e22b5281a84b17577ca33..7c1ab86c199b2f586a286fc9f41748da42a47877 100644 (file)
@@ -99,6 +99,41 @@ bool wxMSWEventLoopBase::GetNextMessage(WXMSG* msg)
     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
@@ -289,6 +324,18 @@ bool wxGUIEventLoop::Dispatch()
     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
@@ -318,22 +365,39 @@ void wxConsoleEventLoop::WakeUp()
 #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;
 }
index ec51ee972bb7c238af064c9d0a1825c28dd2c622..45aad41e2539f5d83a58412669dc3c3e4c9df759 100644 (file)
@@ -48,6 +48,18 @@ void wxGUIEventLoop::WakeUp()
     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;
@@ -95,17 +107,33 @@ bool wxGUIEventLoop::Dispatch()
             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;
+    }
+}
+
index 01bd21e9820fd9cf62c8fd77d7304a7f43ca22ed..5dc164d1574eebfa0d5e890302ef85b442a50da6 100644 (file)
@@ -135,6 +135,11 @@ bool wxGUIEventLoop::Dispatch()
     return false;
 }
 
+int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
+{
+    return -1;
+}
+
 void wxGUIEventLoop::WakeUp()
 {
     return;
index fc1f469ae427e6f626902b971c2377d0a119836d..7f27c1c2a216acba8033c177be65510ad074e52d 100644 (file)
@@ -149,30 +149,34 @@ bool wxConsoleEventLoop::Pending() const
 
 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()