summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vcl/README.scheduler9
-rw-r--r--vcl/inc/win/saltimer.h20
-rw-r--r--vcl/win/app/salinst.cxx11
-rw-r--r--vcl/win/app/saltimer.cxx34
-rw-r--r--vcl/win/window/salframe.cxx11
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