From f740cc38817430c6989182e5d1d970fb043f9b4a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 2 Mar 2014 18:58:00 +0000 Subject: [PATCH] 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 --- include/wx/cocoa/evtloop.h | 2 +- include/wx/evtloop.h | 19 +++++++++++++-- include/wx/gtk/evtloop.h | 2 +- include/wx/msw/evtloop.h | 2 +- include/wx/msw/evtloopconsole.h | 4 ++- include/wx/osx/core/evtloop.h | 4 +-- include/wx/unix/evtloop.h | 2 +- src/cocoa/evtloop.mm | 23 ++---------------- src/common/evtloopcmn.cpp | 43 +++++++++++++++++++++++++++++++++ src/dfb/evtloop.cpp | 22 ++--------------- src/gtk/evtloop.cpp | 38 ++--------------------------- src/gtk1/evtloop.cpp | 28 ++------------------- src/motif/evtloop.cpp | 9 ++----- src/msw/evtloop.cpp | 24 ++---------------- src/msw/evtloopconsole.cpp | 5 ++++ src/os2/evtloop.cpp | 25 +++---------------- src/osx/core/evtloop_cf.cpp | 31 ++---------------------- src/unix/evtloopunix.cpp | 4 +++ src/x11/evtloop.cpp | 9 ++----- 19 files changed, 97 insertions(+), 199 deletions(-) diff --git a/include/wx/cocoa/evtloop.h b/include/wx/cocoa/evtloop.h index 366e46cb1b..2196ce41e3 100644 --- a/include/wx/cocoa/evtloop.h +++ b/include/wx/cocoa/evtloop.h @@ -24,10 +24,10 @@ public: virtual bool Dispatch(); virtual int DispatchTimeout(unsigned long timeout); virtual void WakeUp() { } - virtual bool YieldFor(long eventsToProcess); protected: virtual int DoRun(); + virtual void DoYieldFor(long eventsToProcess); int m_exitcode; diff --git a/include/wx/evtloop.h b/include/wx/evtloop.h index 8dd5d6eb7b..0482504ae6 100644 --- a/include/wx/evtloop.h +++ b/include/wx/evtloop.h @@ -153,7 +153,12 @@ public: // may result in calling the same event handler again), use // with _extreme_ care or, better, don't use at all! 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 virtual bool IsYielding() const @@ -182,6 +187,16 @@ protected: // real implementation of Run() 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 happens normally (because of Exit() call) or abnormally (because of // an exception thrown from inside the loop) @@ -313,10 +328,10 @@ public: } } virtual void WakeUp() { } - virtual bool YieldFor(long eventsToProcess); protected: virtual int DoRun(); + virtual void DoYieldFor(long eventsToProcess); // the pointer to the port specific implementation class wxEventLoopImpl *m_impl; diff --git a/include/wx/gtk/evtloop.h b/include/wx/gtk/evtloop.h index ba8db406d5..cb078f664f 100644 --- a/include/wx/gtk/evtloop.h +++ b/include/wx/gtk/evtloop.h @@ -26,13 +26,13 @@ public: virtual bool Dispatch(); virtual int DispatchTimeout(unsigned long timeout); virtual void WakeUp(); - virtual bool YieldFor(long eventsToProcess); void StoreGdkEventForLaterProcessing(GdkEvent* ev) { m_arrGdkEvents.Add(ev); } protected: virtual int DoRun(); + virtual void DoYieldFor(long eventsToProcess); private: // the exit code of this event loop diff --git a/include/wx/msw/evtloop.h b/include/wx/msw/evtloop.h index dee2c03db3..4ccb2a610b 100644 --- a/include/wx/msw/evtloop.h +++ b/include/wx/msw/evtloop.h @@ -54,10 +54,10 @@ public: virtual bool Dispatch(); virtual int DispatchTimeout(unsigned long timeout); virtual void WakeUp(); - virtual bool YieldFor(long eventsToProcess); protected: virtual void OnNextIteration(); + virtual void DoYieldFor(long eventsToProcess); private: // check if the given window is a child of ms_winCritical (which must be diff --git a/include/wx/msw/evtloopconsole.h b/include/wx/msw/evtloopconsole.h index 36da6f640a..01d77805f7 100644 --- a/include/wx/msw/evtloopconsole.h +++ b/include/wx/msw/evtloopconsole.h @@ -40,10 +40,12 @@ public: virtual bool Dispatch(); virtual int DispatchTimeout(unsigned long timeout); virtual void WakeUp(); - virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; } // Windows-specific function to process a single message virtual void ProcessMessage(WXMSG *msg); + +protected: + virtual void DoYieldFor(long eventsToProcess); }; #endif // wxUSE_CONSOLE_EVENTLOOP diff --git a/include/wx/osx/core/evtloop.h b/include/wx/osx/core/evtloop.h index d2ff91d4c2..2b002e087d 100644 --- a/include/wx/osx/core/evtloop.h +++ b/include/wx/osx/core/evtloop.h @@ -42,8 +42,6 @@ public: // to it (can be called from non main thread) virtual void WakeUp(); - virtual bool YieldFor(long eventsToProcess); - bool ShouldProcessIdleEvents() const { return m_processIdleEvents ; } #if wxUSE_UIACTIONSIMULATOR @@ -57,6 +55,8 @@ protected: // terminating when Exit() is called virtual int DoRun(); + virtual void DoYieldFor(long eventsToProcess); + void CommonModeObserverCallBack(CFRunLoopObserverRef observer, int activity); void DefaultModeObserverCallBack(CFRunLoopObserverRef observer, int activity); diff --git a/include/wx/unix/evtloop.h b/include/wx/unix/evtloop.h index 2b91c72375..46891ef447 100644 --- a/include/wx/unix/evtloop.h +++ b/include/wx/unix/evtloop.h @@ -38,10 +38,10 @@ public: virtual int DispatchTimeout(unsigned long timeout); virtual void WakeUp(); virtual bool IsOk() const { return m_dispatcher != NULL; } - virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; } protected: virtual void OnNextIteration(); + virtual void DoYieldFor(long eventsToProcess); private: // pipe used for wake up messages: when a child thread wants to wake up diff --git a/src/cocoa/evtloop.mm b/src/cocoa/evtloop.mm index 632e5f7fb5..8e34eb0143 100644 --- a/src/cocoa/evtloop.mm +++ b/src/cocoa/evtloop.mm @@ -111,17 +111,8 @@ int wxGUIEventLoop::DispatchTimeout(unsigned long timeout) 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 while (1) { @@ -157,15 +148,5 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) the main thread waits and then notify the main thread by posting an event. */ - if (wxTheApp) - wxTheApp->ProcessPendingEvents(); - -#if wxUSE_LOG - // let the logs be flashed again - wxLog::Resume(); -#endif // wxUSE_LOG - - m_isInsideYield = false; - - return true; + wxEventLoopBase::DoYieldFor(eventsToProcess); } diff --git a/src/common/evtloopcmn.cpp b/src/common/evtloopcmn.cpp index f7b5138cc2..9d29048a78 100644 --- a/src/common/evtloopcmn.cpp +++ b/src/common/evtloopcmn.cpp @@ -116,6 +116,49 @@ bool wxEventLoopBase::Yield(bool onlyIfNeeded) 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 wxEventLoopSource* diff --git a/src/dfb/evtloop.cpp b/src/dfb/evtloop.cpp index 9dc00616db..ac18c5b438 100644 --- a/src/dfb/evtloop.cpp +++ b/src/dfb/evtloop.cpp @@ -202,20 +202,8 @@ wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer() // 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 // process all pending events: @@ -230,11 +218,5 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) // OnUpdateUI() which is a nice (and desired) side effect) while ( ProcessIdle() ) {} -#if wxUSE_LOG - wxLog::Resume(); -#endif // wxUSE_LOG - - m_isInsideYield = false; - - return true; + wxEventLoopBase::DoYieldFor(eventsToProcess); } diff --git a/src/gtk/evtloop.cpp b/src/gtk/evtloop.cpp index 4c93056000..6be2d7ac40 100644 --- a/src/gtk/evtloop.cpp +++ b/src/gtk/evtloop.cpp @@ -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 // categorizes the events and using m_eventsToProcessInsideYield decides // if an event should be processed immediately or not @@ -393,15 +376,7 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) gtk_main_iteration(); gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL); - // Process all pending events too, this is consistent with wxMSW behaviour - // 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(); + wxEventLoopBase::DoYieldFor(eventsToProcess); if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD) { @@ -429,13 +404,4 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) } m_arrGdkEvents.Clear(); - -#if wxUSE_LOG - // let the logs be flashed again - wxLog::Resume(); -#endif - - m_isInsideYield = false; - - return true; } diff --git a/src/gtk1/evtloop.cpp b/src/gtk1/evtloop.cpp index fa0e6c7f6e..0e73c8cea5 100644 --- a/src/gtk1/evtloop.cpp +++ b/src/gtk1/evtloop.cpp @@ -150,29 +150,12 @@ bool wxGUIEventLoop::Dispatch() // 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 // never finish. 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 while (gtk_events_pending()) gtk_main_iteration(); @@ -185,14 +168,7 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) // return value of Processidle(). ProcessIdle(); -#if wxUSE_LOG - // let the logs be flashed again - wxLog::Resume(); -#endif - - m_isInsideYield = false; - - return true; + wxEventLoopBase::DoYieldFor(eventsToProcess); } class wxGUIEventLoopSourcesManager : public wxEventLoopSourcesManagerBase diff --git a/src/motif/evtloop.cpp b/src/motif/evtloop.cpp index 85144e440b..2b0296ea92 100644 --- a/src/motif/evtloop.cpp +++ b/src/motif/evtloop.cpp @@ -130,18 +130,13 @@ void wxGUIEventLoop::ScheduleExit(int rc) ::wxBreakDispatch(); } -bool wxGUIEventLoop::YieldFor(long eventsToProcess) +void wxGUIEventLoop::DoYieldFor(long eventsToProcess) { - m_isInsideYield = true; - m_eventsToProcessInsideYield = eventsToProcess; - while (wxTheApp && wxTheApp->Pending()) // TODO: implement event filtering using the eventsToProcess mask wxTheApp->Dispatch(); - m_isInsideYield = false; - - return true; + wxEventLoopBase::DoYieldFor(eventsToProcess); } // ---------------------------------------------------------------------------- diff --git a/src/msw/evtloop.cpp b/src/msw/evtloop.cpp index f39ebc50b0..8ac1b576d5 100644 --- a/src/msw/evtloop.cpp +++ b/src/msw/evtloop.cpp @@ -34,7 +34,6 @@ #include "wx/thread.h" #include "wx/except.h" #include "wx/msw/private.h" -#include "wx/scopeguard.h" #include "wx/tooltip.h" #if wxUSE_THREADS @@ -264,23 +263,8 @@ void wxGUIEventLoop::WakeUp() #include 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 // the main event loop in order to stop it MSG msg; @@ -434,9 +418,7 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) } } - // if there are pending events, we must process them. - if ( eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp ) - wxTheApp->ProcessPendingEvents(); + wxEventLoopBase::DoYieldFor(eventsToProcess); // put back unprocessed events in the queue DWORD id = GetCurrentThreadId(); @@ -447,6 +429,4 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) } m_arrMSG.Clear(); - - return true; } diff --git a/src/msw/evtloopconsole.cpp b/src/msw/evtloopconsole.cpp index 5421b86c43..2be3f9c80f 100644 --- a/src/msw/evtloopconsole.cpp +++ b/src/msw/evtloopconsole.cpp @@ -162,4 +162,9 @@ int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout) return !m_shouldExit; } +void wxConsoleEventLoop::DoYieldFor(long eventsToProcess) +{ + wxEventLoopBase::DoYieldFor(eventsToProcess); +} + #endif // wxUSE_CONSOLE_EVENTLOOP diff --git a/src/os2/evtloop.cpp b/src/os2/evtloop.cpp index 1ab8cb8fca..82e73e0da2 100644 --- a/src/os2/evtloop.cpp +++ b/src/os2/evtloop.cpp @@ -368,20 +368,11 @@ bool wxGUIEventLoop::Dispatch() // // Yield to incoming messages // -bool wxGUIEventLoop::YieldFor(long eventsToProcess) +void wxGUIEventLoop::DoYieldFor(long eventsToProcess) { HAB vHab = 0; 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 // if we see a WM_QUIT. (?) @@ -397,20 +388,10 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) break; } - // - // If they are pending events, we must process them. - // + wxEventLoopBase::DoYieldFor(eventsToProcess); + if (eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp) { - wxTheApp->ProcessPendingEvents(); wxTheApp->HandleSockets(); } - - // - // Let the logs be flashed again - // - wxLog::Resume(); - m_isInsideYield = false; - - return true; } // end of wxYield diff --git a/src/osx/core/evtloop_cf.cpp b/src/osx/core/evtloop_cf.cpp index 4718fa7ae8..de0bf39074 100644 --- a/src/osx/core/evtloop_cf.cpp +++ b/src/osx/core/evtloop_cf.cpp @@ -184,26 +184,8 @@ void wxMacWakeUp() #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: while ( DoProcessEvents() == 1 ) ; @@ -213,16 +195,7 @@ bool wxCFEventLoop::YieldFor(long eventsToProcess) // OnUpdateUI() which is a nice (and desired) side effect) while ( ProcessIdle() ) {} - // if there are pending events, we must process them. - if ( eventsToProcess == wxEVT_CATEGORY_ALL && wxTheApp ) - wxTheApp->ProcessPendingEvents(); - -#if wxUSE_LOG - wxLog::Resume(); -#endif // wxUSE_LOG - m_isInsideYield = false; - - return true; + wxEventLoopBase::DoYieldFor(eventsToProcess); } // implement/override base class pure virtual diff --git a/src/unix/evtloopunix.cpp b/src/unix/evtloopunix.cpp index daeac691d1..bea039ef70 100644 --- a/src/unix/evtloopunix.cpp +++ b/src/unix/evtloopunix.cpp @@ -210,6 +210,10 @@ void wxConsoleEventLoop::OnNextIteration() wxTheApp->CheckSignal(); } +void wxConsoleEventLoop::DoYieldFor(long eventsToProcess) +{ + wxEventLoopBase::DoYieldFor(eventsToProcess); +} wxEventLoopBase *wxConsoleAppTraits::CreateEventLoop() { diff --git a/src/x11/evtloop.cpp b/src/x11/evtloop.cpp index 9c9d699571..c6c85a9565 100644 --- a/src/x11/evtloop.cpp +++ b/src/x11/evtloop.cpp @@ -242,7 +242,7 @@ bool wxGUIEventLoop::Dispatch() return true; } -bool wxGUIEventLoop::YieldFor(long eventsToProcess) +void wxGUIEventLoop::DoYieldFor(long eventsToProcess) { // Sometimes only 2 yields seem // to do the trick, e.g. in the @@ -250,9 +250,6 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) int i; for (i = 0; i < 2; i++) { - m_isInsideYield = true; - m_eventsToProcessInsideYield = eventsToProcess; - // Call dispatch at least once so that sockets // can be tested wxTheApp->Dispatch(); @@ -266,8 +263,6 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess) #endif ProcessIdle(); - m_isInsideYield = false; + wxEventLoopBase::DoYieldFor(eventsToProcess); } - - return true; }