diff options
-rw-r--r-- | vcl/README.scheduler | 9 | ||||
-rw-r--r-- | vcl/inc/win/saltimer.h | 20 | ||||
-rw-r--r-- | vcl/win/app/salinst.cxx | 11 | ||||
-rw-r--r-- | vcl/win/app/saltimer.cxx | 34 | ||||
-rw-r--r-- | vcl/win/window/salframe.cxx | 11 |
5 files changed, 83 insertions, 2 deletions
diff --git a/vcl/README.scheduler b/vcl/README.scheduler index a052dd420c74..566a88629301 100644 --- a/vcl/README.scheduler +++ b/vcl/README.scheduler @@ -187,6 +187,15 @@ the system message wasn't already our timer. As a result we can also skip the polling. All this is one more reason to drop the single message processing in favour of always processing all pending (system) events. +There is an other special case, we have to handle: window updates during move +and resize of windows. These system actions run in their own nested message +loop. So we have to completely switch to timers, even for 0ms. But these +posted events prevent any event processing, while we're busy. The only viable +solution seems to be to switch to WM_TIMER based timers, as these generate +messages with the lowest system priority (but they don't allow 0ms timeouts). +So processing slows down during resize and move, but we gain working painting, +even when busy. + An additional workaround is implemented for the delayed queuing of posted messages, where PeekMessage in WinSalTimer::Stop() won't be able remove the just posted timer callback message. See "General: invalidation of elapsed diff --git a/vcl/inc/win/saltimer.h b/vcl/inc/win/saltimer.h index 68973e1cadc3..d762b51b6716 100644 --- a/vcl/inc/win/saltimer.h +++ b/vcl/inc/win/saltimer.h @@ -31,13 +31,20 @@ class WinSalTimer final : public SalTimer, protected VersionedEvent // for access to ImplHandleElapsedTimer friend bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents ); + /** + * Identifier for our SetTimer based timer + */ + static constexpr UINT_PTR m_aWmTimerId = 0xdeadbeef; + HANDLE m_nTimerId; ///< Windows timer id bool m_bDirectTimeout; ///< timeout can be processed directly + bool m_bForceRealTimer; ///< enforce using a real timer for 0ms void ImplStart( sal_uIntPtr nMS ); void ImplStop(); void ImplHandleTimerEvent( WPARAM aWPARAM ); void ImplHandleElapsedTimer(); + void ImplHandle_WM_TIMER( WPARAM aWPARAM ); public: WinSalTimer(); @@ -48,6 +55,14 @@ public: inline bool IsDirectTimeout() const; inline bool HasTimerElapsed() const; + + /** + * Enforces the usage of a real timer instead of the message queue + * + * Needed for Window resize processing, as this starts a modal event loop. + */ + void SetForceRealTimer( bool bVal ); + inline bool GetForceRealTimer() const; }; inline bool WinSalTimer::IsDirectTimeout() const @@ -60,6 +75,11 @@ inline bool WinSalTimer::HasTimerElapsed() const return m_bDirectTimeout || ExistsValidEvent(); } +inline bool WinSalTimer::GetForceRealTimer() const +{ + return m_bForceRealTimer; +} + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx index ade332297fc6..54598a420040 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -530,6 +530,10 @@ bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents ) } } + // we're back in the main loop after resize or move + if ( pTimer ) + pTimer->SetForceRealTimer( false ); + return bWasMsg; } @@ -665,6 +669,13 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i pTimer->ImplHandleTimerEvent( wParam ); break; } + case WM_TIMER: + { + WinSalTimer *const pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer ); + assert( pTimer != nullptr ); + pTimer->ImplHandle_WM_TIMER( wParam ); + break; + } } return nRet; diff --git a/vcl/win/app/saltimer.cxx b/vcl/win/app/saltimer.cxx index fe22d53db8c8..9d20c70bdb5a 100644 --- a/vcl/win/app/saltimer.cxx +++ b/vcl/win/app/saltimer.cxx @@ -41,12 +41,15 @@ void WinSalTimer::ImplStop() const WinSalInstance *pInst = pSalData->mpInstance; assert( !pInst || pSalData->mnAppThreadId == GetCurrentThreadId() ); + if ( m_bForceRealTimer && m_bDirectTimeout ) + KillTimer( GetSalData()->mpInstance->mhComWnd, m_aWmTimerId ); + m_bDirectTimeout = false; + const HANDLE hTimer = m_nTimerId; if ( nullptr == hTimer ) return; m_nTimerId = nullptr; - m_bDirectTimeout = false; DeleteTimerQueueTimer( nullptr, hTimer, INVALID_HANDLE_VALUE ); // Keep InvalidateEvent after DeleteTimerQueueTimer, because the event id // is set in SalTimerProc, which DeleteTimerQueueTimer will finish or cancel. @@ -73,13 +76,21 @@ void WinSalTimer::ImplStart( sal_uLong nMS ) if ( !m_bDirectTimeout ) CreateTimerQueueTimer(&m_nTimerId, nullptr, SalTimerProc, this, nMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE); - // We don't need any wakeup message, as this code can just run in the + else if ( m_bForceRealTimer ) + { + // so we don't block the nested message queue in move and resize + // with posted 0ms SAL_MSG_TIMER_CALLBACK messages + SetTimer( GetSalData()->mpInstance->mhComWnd, m_aWmTimerId, + USER_TIMER_MINIMUM, nullptr ); + } + // we don't need any wakeup message, as this code can just run in the // main thread! } WinSalTimer::WinSalTimer() : m_nTimerId( nullptr ) , m_bDirectTimeout( false ) + , m_bForceRealTimer( false ) { } @@ -156,4 +167,23 @@ void WinSalTimer::ImplHandleTimerEvent( const WPARAM aWPARAM ) ImplHandleElapsedTimer(); } +void WinSalTimer::SetForceRealTimer( const bool bVal ) +{ + if ( m_bForceRealTimer == bVal ) + return; + + m_bForceRealTimer = bVal; + + // we need a real timer, as m_bDirectTimeout won't be processed + if ( bVal && m_bDirectTimeout ) + Start( 0 ); +} + +void WinSalTimer::ImplHandle_WM_TIMER( const WPARAM aWPARAM ) +{ + assert( m_aWmTimerId == aWPARAM ); + if ( m_aWmTimerId == aWPARAM && m_bDirectTimeout && m_bForceRealTimer ) + ImplHandleElapsedTimer(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx index 622fa7bba2b2..dcbfda8163a8 100644 --- a/vcl/win/window/salframe.cxx +++ b/vcl/win/window/salframe.cxx @@ -3977,6 +3977,10 @@ static void ImplHandleSizeMsg( HWND hWnd, WPARAM wParam, LPARAM lParam ) ImplSaveFrameState( pFrame ); // Call Hdl ImplCallSizeHdl( hWnd ); + + WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer ); + if ( pTimer ) + pTimer->SetForceRealTimer( true ); } } } @@ -4782,6 +4786,13 @@ static bool ImplHandleSysCommand( HWND hWnd, WPARAM wParam, LPARAM lParam ) } } + if ( nCommand == SC_MOVE ) + { + WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer ); + if ( pTimer ) + pTimer->SetForceRealTimer( true ); + } + if ( nCommand == SC_KEYMENU ) { // do not process SC_KEYMENU if we have a native menu |