Refactor YieldFor() to avoid code duplication among the ports.

Don't repeat the same code in all the ports, move it to the common base class
and add a new virtual DoYieldFor() for the really port-specific code.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76061 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2014-03-02 18:58:00 +00:00
parent 632c106cd5
commit f740cc3881
19 changed files with 97 additions and 199 deletions

View File

@@ -24,10 +24,10 @@ public:
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout); virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp() { } virtual void WakeUp() { }
virtual bool YieldFor(long eventsToProcess);
protected: protected:
virtual int DoRun(); virtual int DoRun();
virtual void DoYieldFor(long eventsToProcess);
int m_exitcode; int m_exitcode;

View File

@@ -153,7 +153,12 @@ public:
// may result in calling the same event handler again), use // may result in calling the same event handler again), use
// with _extreme_ care or, better, don't use at all! // with _extreme_ care or, better, don't use at all!
bool Yield(bool onlyIfNeeded = false); bool Yield(bool onlyIfNeeded = false);
virtual bool YieldFor(long eventsToProcess) = 0;
// more selective version of Yield()
//
// notice that it is virtual for backwards-compatibility but new code
// should override DoYieldFor() and not YieldFor() itself
virtual bool YieldFor(long eventsToProcess);
// returns true if the main thread is inside a Yield() call // returns true if the main thread is inside a Yield() call
virtual bool IsYielding() const virtual bool IsYielding() const
@@ -182,6 +187,16 @@ protected:
// real implementation of Run() // real implementation of Run()
virtual int DoRun() = 0; virtual int DoRun() = 0;
// And the real, port-specific, implementation of YieldFor().
//
// The base class version is pure virtual to ensure that it is overridden
// in the derived classes but does have an implementation which processes
// pending events in wxApp if eventsToProcess allows it, and so should be
// called from the overridden version at an appropriate place (i.e. after
// processing the native events but before doing anything else that could
// be affected by pending events dispatching).
virtual void DoYieldFor(long eventsToProcess) = 0;
// this function should be called before the event loop terminates, whether // this function should be called before the event loop terminates, whether
// this happens normally (because of Exit() call) or abnormally (because of // this happens normally (because of Exit() call) or abnormally (because of
// an exception thrown from inside the loop) // an exception thrown from inside the loop)
@@ -313,10 +328,10 @@ public:
} }
} }
virtual void WakeUp() { } virtual void WakeUp() { }
virtual bool YieldFor(long eventsToProcess);
protected: protected:
virtual int DoRun(); virtual int DoRun();
virtual void DoYieldFor(long eventsToProcess);
// the pointer to the port specific implementation class // the pointer to the port specific implementation class
wxEventLoopImpl *m_impl; wxEventLoopImpl *m_impl;

View File

@@ -26,13 +26,13 @@ public:
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout); virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp(); virtual void WakeUp();
virtual bool YieldFor(long eventsToProcess);
void StoreGdkEventForLaterProcessing(GdkEvent* ev) void StoreGdkEventForLaterProcessing(GdkEvent* ev)
{ m_arrGdkEvents.Add(ev); } { m_arrGdkEvents.Add(ev); }
protected: protected:
virtual int DoRun(); virtual int DoRun();
virtual void DoYieldFor(long eventsToProcess);
private: private:
// the exit code of this event loop // the exit code of this event loop

View File

@@ -54,10 +54,10 @@ public:
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout); virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp(); virtual void WakeUp();
virtual bool YieldFor(long eventsToProcess);
protected: protected:
virtual void OnNextIteration(); virtual void OnNextIteration();
virtual void DoYieldFor(long eventsToProcess);
private: private:
// check if the given window is a child of ms_winCritical (which must be // check if the given window is a child of ms_winCritical (which must be

View File

@@ -40,10 +40,12 @@ public:
virtual bool Dispatch(); virtual bool Dispatch();
virtual int DispatchTimeout(unsigned long timeout); virtual int DispatchTimeout(unsigned long timeout);
virtual void WakeUp(); virtual void WakeUp();
virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; }
// Windows-specific function to process a single message // Windows-specific function to process a single message
virtual void ProcessMessage(WXMSG *msg); virtual void ProcessMessage(WXMSG *msg);
protected:
virtual void DoYieldFor(long eventsToProcess);
}; };
#endif // wxUSE_CONSOLE_EVENTLOOP #endif // wxUSE_CONSOLE_EVENTLOOP

View File

@@ -42,8 +42,6 @@ public:
// to it (can be called from non main thread) // to it (can be called from non main thread)
virtual void WakeUp(); virtual void WakeUp();
virtual bool YieldFor(long eventsToProcess);
bool ShouldProcessIdleEvents() const { return m_processIdleEvents ; } bool ShouldProcessIdleEvents() const { return m_processIdleEvents ; }
#if wxUSE_UIACTIONSIMULATOR #if wxUSE_UIACTIONSIMULATOR
@@ -57,6 +55,8 @@ protected:
// terminating when Exit() is called // terminating when Exit() is called
virtual int DoRun(); virtual int DoRun();
virtual void DoYieldFor(long eventsToProcess);
void CommonModeObserverCallBack(CFRunLoopObserverRef observer, int activity); void CommonModeObserverCallBack(CFRunLoopObserverRef observer, int activity);
void DefaultModeObserverCallBack(CFRunLoopObserverRef observer, int activity); void DefaultModeObserverCallBack(CFRunLoopObserverRef observer, int activity);

View File

@@ -38,10 +38,10 @@ public:
virtual int DispatchTimeout(unsigned long timeout); 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; }
virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; }
protected: protected:
virtual void OnNextIteration(); virtual void OnNextIteration();
virtual void DoYieldFor(long eventsToProcess);
private: private:
// pipe used for wake up messages: when a child thread wants to wake up // pipe used for wake up messages: when a child thread wants to wake up

View File

@@ -111,17 +111,8 @@ int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
return true; return true;
} }
bool wxGUIEventLoop::YieldFor(long eventsToProcess) void wxGUIEventLoop::DoYieldFor(long eventsToProcess)
{ {
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
// normally result in message boxes popping up &c
wxLog::Suspend();
#endif // wxUSE_LOG
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
// Run the event loop until it is out of events // Run the event loop until it is out of events
while (1) while (1)
{ {
@@ -157,15 +148,5 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
the main thread waits and then notify the main thread by posting the main thread waits and then notify the main thread by posting
an event. an event.
*/ */
if (wxTheApp) wxEventLoopBase::DoYieldFor(eventsToProcess);
wxTheApp->ProcessPendingEvents();
#if wxUSE_LOG
// let the logs be flashed again
wxLog::Resume();
#endif // wxUSE_LOG
m_isInsideYield = false;
return true;
} }

View File

@@ -116,6 +116,49 @@ bool wxEventLoopBase::Yield(bool onlyIfNeeded)
return YieldFor(wxEVT_CATEGORY_ALL); return YieldFor(wxEVT_CATEGORY_ALL);
} }
bool wxEventLoopBase::YieldFor(long eventsToProcess)
{
#if wxUSE_THREADS
if ( !wxThread::IsMain() )
{
// Don't ever dispatch events from non-main threads.
return false;
}
#endif // wxUSE_THREADS
// set the flag and don't forget to reset it before returning
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
wxON_BLOCK_EXIT_SET(m_isInsideYield, false);
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
// normally result in message boxes popping up &c
wxLog::Suspend();
// ensure the logs will be flashed again when we exit
wxON_BLOCK_EXIT0(wxLog::Resume);
#endif
DoYieldFor(eventsToProcess);
return true;
}
void wxEventLoopBase::DoYieldFor(long eventsToProcess)
{
// Normally yielding dispatches not only the pending native events, but
// also the events pending in wxWidgets itself.
//
// Notice however that we must not do it if we're asked to process only the
// events of specific kind, as pending events could be of any kind at all
// (ideal would be to have a filtering version of ProcessPendingEvents()
// too but we don't have this right now).
if ( eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp )
wxTheApp->ProcessPendingEvents();
}
#if wxUSE_EVENTLOOP_SOURCE #if wxUSE_EVENTLOOP_SOURCE
wxEventLoopSource* wxEventLoopSource*

View File

@@ -202,20 +202,8 @@ wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer()
// events dispatch and loop handling // events dispatch and loop handling
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool wxGUIEventLoop::YieldFor(long eventsToProcess) void wxGUIEventLoop::DoYieldFor(long eventsToProcess)
{ {
#if wxUSE_THREADS
if ( !wxThread::IsMain() )
return true; // can't process events from other threads
#endif // wxUSE_THREADS
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
#if wxUSE_LOG
wxLog::Suspend();
#endif // wxUSE_LOG
// TODO: implement event filtering using the eventsToProcess mask // TODO: implement event filtering using the eventsToProcess mask
// process all pending events: // process all pending events:
@@ -230,11 +218,5 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
// OnUpdateUI() which is a nice (and desired) side effect) // OnUpdateUI() which is a nice (and desired) side effect)
while ( ProcessIdle() ) {} while ( ProcessIdle() ) {}
#if wxUSE_LOG wxEventLoopBase::DoYieldFor(eventsToProcess);
wxLog::Resume();
#endif // wxUSE_LOG
m_isInsideYield = false;
return true;
} }

View File

@@ -361,25 +361,8 @@ static void wxgtk_main_do_event(GdkEvent* event, void* data)
} }
} }
bool wxGUIEventLoop::YieldFor(long eventsToProcess) void wxGUIEventLoop::DoYieldFor(long eventsToProcess)
{ {
#if wxUSE_THREADS
if ( !wxThread::IsMain() )
{
// can't call gtk_main_iteration() from other threads like this
return true;
}
#endif // wxUSE_THREADS
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
// normally result in message boxes popping up &c
wxLog::Suspend();
#endif
// temporarily replace the global GDK event handler with our function, which // temporarily replace the global GDK event handler with our function, which
// categorizes the events and using m_eventsToProcessInsideYield decides // categorizes the events and using m_eventsToProcessInsideYield decides
// if an event should be processed immediately or not // if an event should be processed immediately or not
@@ -393,15 +376,7 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
gtk_main_iteration(); gtk_main_iteration();
gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL); gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
// Process all pending events too, this is consistent with wxMSW behaviour wxEventLoopBase::DoYieldFor(eventsToProcess);
// and the behaviour of wxGTK itself in the previous versions.
//
// Notice however that we must not do it if we're asked to process only the
// events of specific kind, as pending events could be of any kind at all
// (ideal would be to have a filtering version of ProcessPendingEvents()
// too but we don't have this right now).
if ( eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp )
wxTheApp->ProcessPendingEvents();
if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD) if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
{ {
@@ -429,13 +404,4 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
} }
m_arrGdkEvents.Clear(); m_arrGdkEvents.Clear();
#if wxUSE_LOG
// let the logs be flashed again
wxLog::Resume();
#endif
m_isInsideYield = false;
return true;
} }

View File

@@ -150,29 +150,12 @@ bool wxGUIEventLoop::Dispatch()
// wxYield // wxYield
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool wxGUIEventLoop::YieldFor(long eventsToProcess) void wxGUIEventLoop::DoYieldFor(long eventsToProcess)
{ {
#if wxUSE_THREADS
if ( !wxThread::IsMain() )
{
// can't call gtk_main_iteration() from other threads like this
return true;
}
#endif // wxUSE_THREADS
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
// We need to remove idle callbacks or the loop will // We need to remove idle callbacks or the loop will
// never finish. // never finish.
wxTheApp->RemoveIdleTag(); wxTheApp->RemoveIdleTag();
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
// normally result in message boxes popping up &c
wxLog::Suspend();
#endif
// TODO: implement event filtering using the eventsToProcess mask // TODO: implement event filtering using the eventsToProcess mask
while (gtk_events_pending()) while (gtk_events_pending())
gtk_main_iteration(); gtk_main_iteration();
@@ -185,14 +168,7 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
// return value of Processidle(). // return value of Processidle().
ProcessIdle(); ProcessIdle();
#if wxUSE_LOG wxEventLoopBase::DoYieldFor(eventsToProcess);
// let the logs be flashed again
wxLog::Resume();
#endif
m_isInsideYield = false;
return true;
} }
class wxGUIEventLoopSourcesManager : public wxEventLoopSourcesManagerBase class wxGUIEventLoopSourcesManager : public wxEventLoopSourcesManagerBase

View File

@@ -130,18 +130,13 @@ void wxGUIEventLoop::ScheduleExit(int rc)
::wxBreakDispatch(); ::wxBreakDispatch();
} }
bool wxGUIEventLoop::YieldFor(long eventsToProcess) void wxGUIEventLoop::DoYieldFor(long eventsToProcess)
{ {
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
while (wxTheApp && wxTheApp->Pending()) while (wxTheApp && wxTheApp->Pending())
// TODO: implement event filtering using the eventsToProcess mask // TODO: implement event filtering using the eventsToProcess mask
wxTheApp->Dispatch(); wxTheApp->Dispatch();
m_isInsideYield = false; wxEventLoopBase::DoYieldFor(eventsToProcess);
return true;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -34,7 +34,6 @@
#include "wx/thread.h" #include "wx/thread.h"
#include "wx/except.h" #include "wx/except.h"
#include "wx/msw/private.h" #include "wx/msw/private.h"
#include "wx/scopeguard.h"
#include "wx/tooltip.h" #include "wx/tooltip.h"
#if wxUSE_THREADS #if wxUSE_THREADS
@@ -264,23 +263,8 @@ void wxGUIEventLoop::WakeUp()
#include <wx/arrimpl.cpp> #include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(wxMSGArray); WX_DEFINE_OBJARRAY(wxMSGArray);
bool wxGUIEventLoop::YieldFor(long eventsToProcess) void wxGUIEventLoop::DoYieldFor(long eventsToProcess)
{ {
// set the flag and don't forget to reset it before returning
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
wxON_BLOCK_EXIT_SET(m_isInsideYield, false);
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
// normally result in message boxes popping up &c
wxLog::Suspend();
// ensure the logs will be flashed again when we exit
wxON_BLOCK_EXIT0(wxLog::Resume);
#endif // wxUSE_LOG
// we don't want to process WM_QUIT from here - it should be processed in // we don't want to process WM_QUIT from here - it should be processed in
// the main event loop in order to stop it // the main event loop in order to stop it
MSG msg; MSG msg;
@@ -434,9 +418,7 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
} }
} }
// if there are pending events, we must process them. wxEventLoopBase::DoYieldFor(eventsToProcess);
if ( eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp )
wxTheApp->ProcessPendingEvents();
// put back unprocessed events in the queue // put back unprocessed events in the queue
DWORD id = GetCurrentThreadId(); DWORD id = GetCurrentThreadId();
@@ -447,6 +429,4 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
} }
m_arrMSG.Clear(); m_arrMSG.Clear();
return true;
} }

View File

@@ -162,4 +162,9 @@ int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout)
return !m_shouldExit; return !m_shouldExit;
} }
void wxConsoleEventLoop::DoYieldFor(long eventsToProcess)
{
wxEventLoopBase::DoYieldFor(eventsToProcess);
}
#endif // wxUSE_CONSOLE_EVENTLOOP #endif // wxUSE_CONSOLE_EVENTLOOP

View File

@@ -368,20 +368,11 @@ bool wxGUIEventLoop::Dispatch()
// //
// Yield to incoming messages // Yield to incoming messages
// //
bool wxGUIEventLoop::YieldFor(long eventsToProcess) void wxGUIEventLoop::DoYieldFor(long eventsToProcess)
{ {
HAB vHab = 0; HAB vHab = 0;
QMSG vMsg; QMSG vMsg;
//
// Disable log flushing from here because a call to wxYield() shouldn't
// normally result in message boxes popping up &c
//
wxLog::Suspend();
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
// //
// We want to go back to the main message loop // We want to go back to the main message loop
// if we see a WM_QUIT. (?) // if we see a WM_QUIT. (?)
@@ -397,20 +388,10 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
break; break;
} }
// wxEventLoopBase::DoYieldFor(eventsToProcess);
// If they are pending events, we must process them.
//
if (eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp) if (eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp)
{ {
wxTheApp->ProcessPendingEvents();
wxTheApp->HandleSockets(); wxTheApp->HandleSockets();
} }
//
// Let the logs be flashed again
//
wxLog::Resume();
m_isInsideYield = false;
return true;
} // end of wxYield } // end of wxYield

View File

@@ -184,26 +184,8 @@ void wxMacWakeUp()
#endif #endif
bool wxCFEventLoop::YieldFor(long eventsToProcess) void wxCFEventLoop::DoYieldFor(long eventsToProcess)
{ {
#if wxUSE_THREADS
// Yielding from a non-gui thread needs to bail out, otherwise we end up
// possibly sending events in the thread too.
if ( !wxThread::IsMain() )
{
return true;
}
#endif // wxUSE_THREADS
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
#if wxUSE_LOG
// disable log flushing from here because a call to wxYield() shouldn't
// normally result in message boxes popping up &c
wxLog::Suspend();
#endif // wxUSE_LOG
// process all pending events: // process all pending events:
while ( DoProcessEvents() == 1 ) while ( DoProcessEvents() == 1 )
; ;
@@ -213,16 +195,7 @@ bool wxCFEventLoop::YieldFor(long eventsToProcess)
// OnUpdateUI() which is a nice (and desired) side effect) // OnUpdateUI() which is a nice (and desired) side effect)
while ( ProcessIdle() ) {} while ( ProcessIdle() ) {}
// if there are pending events, we must process them. wxEventLoopBase::DoYieldFor(eventsToProcess);
if ( eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp )
wxTheApp->ProcessPendingEvents();
#if wxUSE_LOG
wxLog::Resume();
#endif // wxUSE_LOG
m_isInsideYield = false;
return true;
} }
// implement/override base class pure virtual // implement/override base class pure virtual

View File

@@ -210,6 +210,10 @@ void wxConsoleEventLoop::OnNextIteration()
wxTheApp->CheckSignal(); wxTheApp->CheckSignal();
} }
void wxConsoleEventLoop::DoYieldFor(long eventsToProcess)
{
wxEventLoopBase::DoYieldFor(eventsToProcess);
}
wxEventLoopBase *wxConsoleAppTraits::CreateEventLoop() wxEventLoopBase *wxConsoleAppTraits::CreateEventLoop()
{ {

View File

@@ -242,7 +242,7 @@ bool wxGUIEventLoop::Dispatch()
return true; return true;
} }
bool wxGUIEventLoop::YieldFor(long eventsToProcess) void wxGUIEventLoop::DoYieldFor(long eventsToProcess)
{ {
// Sometimes only 2 yields seem // Sometimes only 2 yields seem
// to do the trick, e.g. in the // to do the trick, e.g. in the
@@ -250,9 +250,6 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
int i; int i;
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
m_isInsideYield = true;
m_eventsToProcessInsideYield = eventsToProcess;
// Call dispatch at least once so that sockets // Call dispatch at least once so that sockets
// can be tested // can be tested
wxTheApp->Dispatch(); wxTheApp->Dispatch();
@@ -266,8 +263,6 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
#endif #endif
ProcessIdle(); ProcessIdle();
m_isInsideYield = false; wxEventLoopBase::DoYieldFor(eventsToProcess);
} }
return true;
} }