summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/win/saldata.hxx12
-rw-r--r--vcl/win/source/app/salinst.cxx5
-rw-r--r--vcl/win/source/app/saltimer.cxx106
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: */