From 9b4759d7b6dfc1ea016db543405c09ae2f0d49db Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 13 Jan 2018 17:33:09 +0100 Subject: [PATCH] Don't rely on getting WM_NULL messages in wxIdleWakeUpModule Since the switch to using an event object for idle handling wakeup, WM_NULLs are not being sent any longer, so wxIdleWakeUpModule didn't do anything, resulting in pending event dispatching being paused while our event loop was not running, as it happened, for example, while the window was resized. See #17579. --- include/wx/msw/app.h | 4 ++++ include/wx/msw/evtloopconsole.h | 4 ++++ src/msw/app.cpp | 10 ++++++++++ src/msw/evtloopconsole.cpp | 5 +++++ src/msw/window.cpp | 21 ++++++++------------- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/include/wx/msw/app.h b/include/wx/msw/app.h index cbd4c09a46..6a8c8baf0d 100644 --- a/include/wx/msw/app.h +++ b/include/wx/msw/app.h @@ -103,6 +103,10 @@ public: // use it. static wxLayoutDirection MSWGetDefaultLayout(wxWindow* parent = NULL); + // Call ProcessPendingEvents() but only if we need to do it, i.e. there was + // a recent call to WakeUpIdle(). + void MSWProcessPendingEventsIfNeeded(); + protected: int m_printMode; // wxPRINT_WINDOWS, wxPRINT_POSTSCRIPT diff --git a/include/wx/msw/evtloopconsole.h b/include/wx/msw/evtloopconsole.h index 17df0a4e7a..87217bc64b 100644 --- a/include/wx/msw/evtloopconsole.h +++ b/include/wx/msw/evtloopconsole.h @@ -30,6 +30,10 @@ public: WXDWORD MSWWaitForThread(WXHANDLE hThread); #endif // wxUSE_THREADS + // Return true if wake up was requested and not handled yet, i.e. if + // m_heventWake is signaled. + bool MSWIsWakeUpRequested(); + protected: // get the next message from queue and return true or return false if we // got WM_QUIT or an error occurred diff --git a/src/msw/app.cpp b/src/msw/app.cpp index 866078a53a..2c3d14273b 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -790,6 +790,16 @@ void wxApp::WakeUpIdle() evtLoop->WakeUp(); } +void wxApp::MSWProcessPendingEventsIfNeeded() +{ + // The cast below is safe as wxEventLoop derives from wxMSWEventLoopBase in + // both console and GUI applications. + wxMSWEventLoopBase * const evtLoop + = static_cast(wxEventLoop::GetActive()); + if ( evtLoop && evtLoop->MSWIsWakeUpRequested() ) + ProcessPendingEvents(); +} + // ---------------------------------------------------------------------------- // other wxApp event handlers // ---------------------------------------------------------------------------- diff --git a/src/msw/evtloopconsole.cpp b/src/msw/evtloopconsole.cpp index c0ba2716fa..869ea888fd 100644 --- a/src/msw/evtloopconsole.cpp +++ b/src/msw/evtloopconsole.cpp @@ -71,6 +71,11 @@ void wxMSWEventLoopBase::WakeUp() wxLogLastError(wxS("SetEvent(wake)")); } +bool wxMSWEventLoopBase::MSWIsWakeUpRequested() +{ + return ::WaitForSingleObject(m_heventWake, 0) == WAIT_OBJECT_0; +} + #if wxUSE_THREADS WXDWORD wxMSWEventLoopBase::MSWWaitForThread(WXHANDLE hThread) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index ea92c52ed0..41e84b5559 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -7511,10 +7511,9 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) #endif // wxUSE_HOTKEY // this class installs a message hook which really wakes up our idle processing -// each time a WM_NULL is received (wxWakeUpIdle does this), even if we're -// sitting inside a local modal loop (e.g. a menu is opened or scrollbar is -// being dragged or even inside ::MessageBox()) and so don't control message -// dispatching otherwise +// each time a message is handled, even if we're sitting inside a local modal +// loop (e.g. a menu is opened or scrollbar is being dragged or even inside +// ::MessageBox()) and so don't control message dispatching otherwise class wxIdleWakeUpModule : public wxModule { public: @@ -7545,15 +7544,11 @@ public: static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam) { - MSG *msg = (MSG*)lParam; - - // only process the message if it is actually going to be removed from - // the message queue, this prevents that the same event from being - // processed multiple times if now someone just called PeekMessage() - if ( msg->message == WM_NULL && wParam == PM_REMOVE ) - { - wxTheApp->ProcessPendingEvents(); - } + // Don't process idle events unless the message is going to be really + // handled, i.e. removed from the queue, as it seems wrong to do it + // just because someone called PeekMessage(PM_NOREMOVE). + if ( wParam == PM_REMOVE ) + wxTheApp->MSWProcessPendingEventsIfNeeded(); return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam); }