1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <win/saldata.hxx>
22 #include <win/saltimer.h>
23 #include <win/salinst.h>
25 #if defined ( __MINGW32__ )
26 #include <sehandler.hxx>
30 #define MAX_SYSPERIOD 65533
32 void CALLBACK
SalTimerProc(PVOID pParameter
, BOOLEAN bTimerOrWaitFired
);
34 // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms687003%28v=vs.85%29.aspx
35 // (and related pages) for details about the Timer Queues.
37 // in order to prevent concurrent execution of ImplSalStartTimer and double
38 // deletion of timer (which is extremely likely, given that
39 // INVALID_HANDLE_VALUE waits for the callback to run on the main thread),
40 // this must run on the main thread too
41 void ImplSalStopTimer()
43 SalData
*const pSalData
= GetSalData();
44 HANDLE hTimer
= pSalData
->mnTimerId
;
47 pSalData
->mnTimerId
= nullptr; // reset so it doesn't restart
48 DeleteTimerQueueTimer(nullptr, hTimer
, INVALID_HANDLE_VALUE
);
49 pSalData
->mnNextTimerTime
= 0;
52 // this needs to run on the main thread
53 while (PeekMessageW(&aMsg
, nullptr, SAL_MSG_TIMER_CALLBACK
, SAL_MSG_TIMER_CALLBACK
, PM_REMOVE
))
55 // just remove all the SAL_MSG_TIMER_CALLBACKs
56 // when the application end, this SAL_MSG_TIMER_CALLBACK start the timer again
57 // and then crashed in "SalTimerProc" when the object "SalData" was deleted
61 void ImplSalStartTimer( sal_uLong nMS
, bool bMutex
)
63 SalData
* pSalData
= GetSalData();
65 // Remember the time of the timer
66 pSalData
->mnTimerMS
= nMS
;
68 pSalData
->mnTimerOrgMS
= nMS
;
70 // duration has to fit into Window's sal_uInt16
71 if (nMS
> MAX_SYSPERIOD
)
74 // cannot change a one-shot timer, so delete it and create new one
75 if (pSalData
->mnTimerId
)
77 DeleteTimerQueueTimer(nullptr, pSalData
->mnTimerId
, INVALID_HANDLE_VALUE
);
78 pSalData
->mnTimerId
= nullptr;
80 CreateTimerQueueTimer(&pSalData
->mnTimerId
, nullptr, SalTimerProc
, nullptr, nMS
, 0, WT_EXECUTEINTIMERTHREAD
);
82 pSalData
->mnNextTimerTime
= pSalData
->mnLastEventTime
+ nMS
;
85 WinSalTimer::~WinSalTimer()
89 void WinSalTimer::Start( sal_uLong nMS
)
91 // switch to main thread
92 SalData
* pSalData
= GetSalData();
93 if ( pSalData
->mpFirstInstance
)
95 if ( pSalData
->mnAppThreadId
!= GetCurrentThreadId() )
97 BOOL
const ret
= PostMessageW(pSalData
->mpFirstInstance
->mhComWnd
, SAL_MSG_STARTTIMER
, 0, (LPARAM
)nMS
);
98 SAL_WARN_IF(0 == ret
, "vcl", "ERROR: PostMessage() failed!");
101 SendMessageW( pSalData
->mpFirstInstance
->mhComWnd
, SAL_MSG_STARTTIMER
, 0, (LPARAM
)nMS
);
104 ImplSalStartTimer( nMS
);
107 void WinSalTimer::Stop()
109 SalData
* pSalData
= GetSalData();
111 assert(pSalData
->mpFirstInstance
);
112 SendMessageW(pSalData
->mpFirstInstance
->mhComWnd
, SAL_MSG_STOPTIMER
, 0, 0);
115 /** This gets invoked from a Timer Queue thread.
117 Don't acquire the SolarMutex to avoid deadlocks, just wake up the main thread
118 at better resolution than 10ms.
120 void CALLBACK
SalTimerProc(PVOID
, BOOLEAN
)
122 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
125 if (__builtin_setjmp(jmpbuf
) == 0)
127 han
.Set(jmpbuf
, NULL
, (__SEHandler::PF
)EXCEPTION_EXECUTE_HANDLER
);
133 SalData
* pSalData
= GetSalData();
135 // always post message when the timer fires, we will remove the ones
136 // that happened during execution of the callback later directly from
138 BOOL
const ret
= PostMessageW(pSalData
->mpFirstInstance
->mhComWnd
, SAL_MSG_TIMER_CALLBACK
, 0, 0);
139 #if OSL_DEBUG_LEVEL > 0
140 if (0 == ret
) // SEH prevents using SAL_WARN here?
141 fputs("ERROR: PostMessage() failed!", stderr
);
144 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
149 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
155 /** Called in the main thread.
157 We assured that by posting the message from the SalTimeProc only, the real
158 call then happens when the main thread gets SAL_MSG_TIMER_CALLBACK.
160 void EmitTimerCallback()
162 SalData
* pSalData
= GetSalData();
163 ImplSVData
* pSVData
= ImplGetSVData();
165 // Test for MouseLeave
168 // Try to acquire the mutex. If we don't get the mutex then we
169 // try this a short time later again.
170 if (pSVData
->mpSalTimer
&& ImplSalYieldMutexTryToAcquire())
172 bool idle
= true; // TODO
173 pSVData
->mpSalTimer
->CallCallback( idle
);
174 ImplSalYieldMutexRelease();
176 // Run the timer again if it was started before, and also
177 // Run the timer in the correct time, if we started this
178 // with a small timeout, because we didn't get the mutex
179 // - but not if mnTimerId is 0, which is set by ImplSalStopTimer()
180 if (pSalData
->mnTimerId
)
181 ImplSalStartTimer(pSalData
->mnTimerOrgMS
);
185 ImplSalStartTimer(10, true);
189 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */