diff options
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/win/saldata.hxx | 12 | ||||
-rw-r--r-- | vcl/win/source/app/salinst.cxx | 5 | ||||
-rw-r--r-- | vcl/win/source/app/saltimer.cxx | 106 |
3 files changed, 80 insertions, 43 deletions
diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx index d047fc54a857..409ca3eb13e6 100644 --- a/vcl/inc/win/saldata.hxx +++ b/vcl/inc/win/saldata.hxx @@ -83,11 +83,11 @@ public: long* mpDitherDiff; // Dither mapping table BYTE* mpDitherLow; // Dither mapping table BYTE* mpDitherHigh; // Dither mapping table - sal_uLong mnTimerMS; // Current Time (in MS) of the Timer - sal_uLong mnTimerOrgMS; // Current Original Time (in MS) + sal_uLong mnTimerMS; // Current Time (in MS) of the Timer + sal_uLong mnTimerOrgMS; // Current Original Time (in MS) DWORD mnNextTimerTime; DWORD mnLastEventTime; - UINT mnTimerId; // windows timer id + HANDLE mnTimerId; ///< Windows timer id bool mbInTimerProc; // timer event is currently being dispatched HHOOK mhSalObjMsgHook; // hook to get interesting msg for SalObject HWND mhWantLeaveMsg; // window handle, that want a MOUSELEAVE message @@ -181,8 +181,7 @@ void ImplSalAcquireYieldMutex( sal_uLong nCount ); LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); -#define SALTIMERPROC_RECURSIVE 0xffffffff -void CALLBACK SalTimerProc( HWND hWnd, UINT nMsg, UINT_PTR nId, DWORD nTime ); +void EmitTimerCallback(bool bAllowRecursive); void SalTestMouseLeave(); bool ImplWriteLastError( DWORD lastError, const char *szApiCall ); @@ -286,6 +285,9 @@ int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 ); // POSTFOCUS-Message; wParam == bFocus; lParam == 0 #define SALOBJ_MSG_POSTFOCUS (WM_USER+161) +// Call the Timer's callback from the main thread +#define SAL_MSG_TIMER_CALLBACK (WM_USER+162) + // A/W-Wrapper BOOL ImplPostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ); BOOL ImplSendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ); diff --git a/vcl/win/source/app/salinst.cxx b/vcl/win/source/app/salinst.cxx index 7a697ae093dd..c8eb1106315e 100644 --- a/vcl/win/source/app/salinst.cxx +++ b/vcl/win/source/app/salinst.cxx @@ -736,7 +736,10 @@ LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lPar rDef = FALSE; break; case SAL_MSG_POSTTIMER: - SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE, lParam ); + EmitTimerCallback(/*bAllowRecursive = */ true); + break; + case SAL_MSG_TIMER_CALLBACK: + EmitTimerCallback(/*bAllowRecursive = */ false); break; } diff --git a/vcl/win/source/app/saltimer.cxx b/vcl/win/source/app/saltimer.cxx index 287ec9addcfc..779c6918647b 100644 --- a/vcl/win/source/app/saltimer.cxx +++ b/vcl/win/source/app/saltimer.cxx @@ -29,25 +29,37 @@ // maximum period #define MAX_SYSPERIOD 65533 +void CALLBACK SalTimerProc(PVOID pParameter, BOOLEAN bTimerOrWaitFired); + +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms687003%28v=vs.85%29.aspx +// (and related pages) for details about the Timer Queues. + +void ImplSalStopTimer(SalData* pSalData) +{ + HANDLE hTimer = pSalData->mnTimerId; + pSalData->mnTimerId = 0; + DeleteTimerQueueTimer(NULL, hTimer, 0); +} + void ImplSalStartTimer( sal_uLong nMS, bool bMutex ) { SalData* pSalData = GetSalData(); // Remember the time of the timer pSalData->mnTimerMS = nMS; - if ( !bMutex ) + if (!bMutex) pSalData->mnTimerOrgMS = nMS; // duration has to fit into Window's sal_uInt16 - if ( nMS > MAX_SYSPERIOD ) + if (nMS > MAX_SYSPERIOD) nMS = MAX_SYSPERIOD; - // kill timer if it exists - if ( pSalData->mnTimerId ) - KillTimer( 0, pSalData->mnTimerId ); + // change if it exists, create if not + if (pSalData->mnTimerId) + ChangeTimerQueueTimer(NULL, pSalData->mnTimerId, nMS, nMS); + else + CreateTimerQueueTimer(&pSalData->mnTimerId, NULL, SalTimerProc, NULL, nMS, nMS, WT_EXECUTEDEFAULT); - // Make a new timer with new period - pSalData->mnTimerId = SetTimer( 0, 0, (UINT)nMS, SalTimerProc ); pSalData->mnNextTimerTime = pSalData->mnLastEventTime + nMS; } @@ -77,13 +89,17 @@ void WinSalTimer::Stop() // If we have a timer, than if ( pSalData->mnTimerId ) { - KillTimer( 0, pSalData->mnTimerId ); - pSalData->mnTimerId = 0; + ImplSalStopTimer(pSalData); pSalData->mnNextTimerTime = 0; } } -void CALLBACK SalTimerProc( HWND, UINT, UINT_PTR nId, DWORD ) +/** This gets invoked from a Timer Queue thread. + +Don't acquire the SolarMutex to avoid deadlocks, just wake up the main thread +at better resolution than 10ms. +*/ +void CALLBACK SalTimerProc(PVOID, BOOLEAN) { #if defined ( __MINGW32__ ) && !defined ( _WIN64 ) jmp_buf jmpbuf; @@ -98,42 +114,58 @@ void CALLBACK SalTimerProc( HWND, UINT, UINT_PTR nId, DWORD ) SalData* pSalData = GetSalData(); ImplSVData* pSVData = ImplGetSVData(); - // Test for MouseLeave - SalTestMouseLeave(); - - bool bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE); - if ( pSVData->mpSalTimer && ! bRecursive ) + // don't allow recursive calls (mbInTimerProc is set when the callback + // is being processed) + if (pSVData->mpSalTimer && !pSalData->mbInTimerProc) { - // Try to acquire the mutex. If we don't get the mutex then we - // try this a short time later again. - if ( ImplSalYieldMutexTryToAcquire() ) - { - bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE); - if ( pSVData->mpSalTimer && ! bRecursive ) - { - pSalData->mbInTimerProc = TRUE; - pSVData->mpSalTimer->CallCallback(); - pSalData->mbInTimerProc = FALSE; - ImplSalYieldMutexRelease(); - - // Run the timer in the correct time, if we start this - // with a small timeout, because we don't get the mutex - if ( pSalData->mnTimerId && - (pSalData->mnTimerMS != pSalData->mnTimerOrgMS) ) - ImplSalStartTimer( pSalData->mnTimerOrgMS, FALSE ); - } - } - else - ImplSalStartTimer( 10, TRUE ); + ImplPostMessage(pSalData->mpFirstInstance->mhComWnd, SAL_MSG_TIMER_CALLBACK, 0, 0); } - } #if defined ( __MINGW32__ ) && !defined ( _WIN64 ) + } han.Reset(); #else + } __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation())) { } #endif } +/** Called in the main thread. + +We assured that by posting the message from the SalTimeProc only, the real +call then happens when the main thread gets SAL_MSG_TIMER_CALLBACK. + +@param bAllowRecursive allows to skip the check that assures that two timeouts +do not overlap. +*/ +void EmitTimerCallback(bool bAllowRecursive) +{ + SalData* pSalData = GetSalData(); + ImplSVData* pSVData = ImplGetSVData(); + + // Test for MouseLeave + SalTestMouseLeave(); + + // Try to acquire the mutex. If we don't get the mutex then we + // try this a short time later again. + if (ImplSalYieldMutexTryToAcquire()) + { + if (pSVData->mpSalTimer && (!pSalData->mbInTimerProc || bAllowRecursive)) + { + pSalData->mbInTimerProc = true; + pSVData->mpSalTimer->CallCallback(); + pSalData->mbInTimerProc = false; + ImplSalYieldMutexRelease(); + + // Run the timer in the correct time, if we start this + // with a small timeout, because we don't get the mutex + if (pSalData->mnTimerId && (pSalData->mnTimerMS != pSalData->mnTimerOrgMS)) + ImplSalStartTimer(pSalData->mnTimerOrgMS, false); + } + } + else + ImplSalStartTimer(10, true); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |