build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / win / app / saltimer.cxx
blob7930ac9e0b6c50ba723dbc0a1aacbcbbe9f71e9c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <svsys.h>
21 #include <win/saldata.hxx>
22 #include <win/saltimer.h>
23 #include <win/salinst.h>
25 #if defined ( __MINGW32__ )
26 #include <sehandler.hxx>
27 #endif
29 // maximum period
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;
45 if (hTimer)
47 pSalData->mnTimerId = nullptr; // reset so it doesn't restart
48 DeleteTimerQueueTimer(nullptr, hTimer, INVALID_HANDLE_VALUE);
49 pSalData->mnNextTimerTime = 0;
51 MSG aMsg;
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;
67 if (!bMutex)
68 pSalData->mnTimerOrgMS = nMS;
70 // duration has to fit into Window's sal_uInt16
71 if (nMS > MAX_SYSPERIOD)
72 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!");
100 else
101 SendMessageW( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
103 else
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 )
123 jmp_buf jmpbuf;
124 __SEHandler han;
125 if (__builtin_setjmp(jmpbuf) == 0)
127 han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
128 #else
129 __try
131 #endif
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
137 // the message queue
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);
142 #endif
144 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
146 han.Reset();
147 #else
149 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
152 #endif
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
166 SalTestMouseLeave();
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);
183 else
185 ImplSalStartTimer(10, true);
189 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */