Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <tools/time.hxx>
21 :
22 : #include <vcl/svapp.hxx>
23 : #include <vcl/timer.hxx>
24 :
25 : #include <saltimer.hxx>
26 : #include <svdata.hxx>
27 : #include <salinst.hxx>
28 :
29 : #define MAX_TIMER_PERIOD ((sal_uLong)0xFFFFFFFF)
30 :
31 : struct ImplTimerData
32 : {
33 : ImplTimerData* mpNext; // Pointer to the next Instance
34 : Timer* mpTimer; // Pointer to VCL Timer instance
35 : sal_uLong mnUpdateTime; // Last Update Time
36 : sal_uLong mnTimerUpdate; // TimerCallbackProcs on stack
37 : bool mbDelete; // Was timer deleted during Update()?
38 : bool mbInTimeout; // Are we in a timeout handler?
39 : };
40 :
41 535 : void Timer::ImplDeInitTimer()
42 : {
43 535 : ImplSVData* pSVData = ImplGetSVData();
44 535 : ImplTimerData* pTimerData = pSVData->mpFirstTimerData;
45 :
46 : // on WNT the timer queue thread needs killing
47 535 : if (pSVData->mpSalTimer)
48 : {
49 469 : pSVData->mpSalTimer->Stop();
50 : }
51 :
52 535 : if ( pTimerData )
53 : {
54 7981 : do
55 : {
56 7981 : ImplTimerData* pTempTimerData = pTimerData;
57 7981 : if ( pTimerData->mpTimer )
58 : {
59 694 : pTimerData->mpTimer->mbActive = false;
60 694 : pTimerData->mpTimer->mpTimerData = NULL;
61 : }
62 7981 : pTimerData = pTimerData->mpNext;
63 7981 : delete pTempTimerData;
64 : }
65 : while ( pTimerData );
66 :
67 447 : pSVData->mpFirstTimerData = NULL;
68 447 : pSVData->mnTimerPeriod = 0;
69 : }
70 :
71 535 : delete pSVData->mpSalTimer;
72 535 : pSVData->mpSalTimer = 0;
73 535 : }
74 :
75 66117 : static void ImplStartTimer( ImplSVData* pSVData, sal_uLong nMS )
76 : {
77 66117 : if ( !nMS )
78 6500 : nMS = 1;
79 :
80 : // Assume underlying timers are recurring timers, if same period - just wait.
81 66117 : if ( nMS != pSVData->mnTimerPeriod )
82 : {
83 56784 : pSVData->mnTimerPeriod = nMS;
84 56784 : pSVData->mpSalTimer->Start( nMS );
85 : }
86 66117 : }
87 :
88 38807 : void Timer::ImplTimerCallbackProc()
89 : {
90 38807 : ImplSVData* pSVData = ImplGetSVData();
91 : ImplTimerData* pTimerData;
92 : ImplTimerData* pPrevTimerData;
93 38807 : sal_uLong nMinPeriod = MAX_TIMER_PERIOD;
94 : sal_uLong nDeltaTime;
95 38807 : sal_uLong nTime = tools::Time::GetSystemTicks();
96 :
97 38807 : if ( pSVData->mbNoCallTimer )
98 38807 : return;
99 :
100 38807 : pSVData->mnTimerUpdate++;
101 38807 : pSVData->mbNotAllTimerCalled = true;
102 :
103 : // find timer where the timer handler needs to be called
104 38807 : pTimerData = pSVData->mpFirstTimerData;
105 397183 : while ( pTimerData )
106 : {
107 : // If the timer is not new, was not deleted, and if it is not in the timeout handler, then
108 : // call the handler as soon as the time is up.
109 636412 : if ( (pTimerData->mnTimerUpdate < pSVData->mnTimerUpdate) &&
110 571730 : !pTimerData->mbDelete && !pTimerData->mbInTimeout )
111 : {
112 : // time has expired
113 254887 : if ( (pTimerData->mnUpdateTime+pTimerData->mpTimer->mnTimeout) <= nTime )
114 : {
115 : // set new update time
116 53005 : pTimerData->mnUpdateTime = nTime;
117 :
118 : // if no AutoTimer than stop
119 53005 : if ( !pTimerData->mpTimer->mbAuto )
120 : {
121 42202 : pTimerData->mpTimer->mbActive = false;
122 42202 : pTimerData->mbDelete = true;
123 : }
124 :
125 : // call Timeout
126 53005 : pTimerData->mbInTimeout = true;
127 53005 : pTimerData->mpTimer->Timeout();
128 53005 : pTimerData->mbInTimeout = false;
129 : }
130 : }
131 :
132 319569 : pTimerData = pTimerData->mpNext;
133 : }
134 :
135 : // determine new time
136 38807 : sal_uLong nNewTime = tools::Time::GetSystemTicks();
137 38807 : pPrevTimerData = NULL;
138 38807 : pTimerData = pSVData->mpFirstTimerData;
139 397183 : while ( pTimerData )
140 : {
141 : // ignore if timer is still in timeout handler
142 319569 : if ( pTimerData->mbInTimeout )
143 : {
144 102 : pPrevTimerData = pTimerData;
145 102 : pTimerData = pTimerData->mpNext;
146 : }
147 : // Was timer destroyed in the meantime?
148 319467 : else if ( pTimerData->mbDelete )
149 : {
150 97308 : if ( pPrevTimerData )
151 96822 : pPrevTimerData->mpNext = pTimerData->mpNext;
152 : else
153 486 : pSVData->mpFirstTimerData = pTimerData->mpNext;
154 97308 : if ( pTimerData->mpTimer )
155 40596 : pTimerData->mpTimer->mpTimerData = NULL;
156 97308 : ImplTimerData* pTempTimerData = pTimerData;
157 97308 : pTimerData = pTimerData->mpNext;
158 97308 : delete pTempTimerData;
159 : }
160 : else
161 : {
162 222159 : pTimerData->mnTimerUpdate = 0;
163 : // determine smallest time slot
164 222159 : if ( pTimerData->mnUpdateTime == nTime )
165 : {
166 24155 : nDeltaTime = pTimerData->mpTimer->mnTimeout;
167 24155 : if ( nDeltaTime < nMinPeriod )
168 18027 : nMinPeriod = nDeltaTime;
169 : }
170 : else
171 : {
172 198004 : nDeltaTime = pTimerData->mnUpdateTime + pTimerData->mpTimer->mnTimeout;
173 198004 : if ( nDeltaTime < nNewTime )
174 6828 : nMinPeriod = 1;
175 : else
176 : {
177 191176 : nDeltaTime -= nNewTime;
178 191176 : if ( nDeltaTime < nMinPeriod )
179 99466 : nMinPeriod = nDeltaTime;
180 : }
181 : }
182 222159 : pPrevTimerData = pTimerData;
183 222159 : pTimerData = pTimerData->mpNext;
184 : }
185 : }
186 :
187 : // delete clock if no more timers available
188 38807 : if ( !pSVData->mpFirstTimerData )
189 : {
190 85 : pSVData->mpSalTimer->Stop();
191 85 : pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
192 : }
193 : else
194 38722 : ImplStartTimer( pSVData, nMinPeriod );
195 :
196 38807 : pSVData->mnTimerUpdate--;
197 38807 : pSVData->mbNotAllTimerCalled = false;
198 : }
199 :
200 663156 : Timer::Timer():
201 : mpTimerData(NULL),
202 : mnTimeout(1),
203 : mbActive(false),
204 663156 : mbAuto(false)
205 : {
206 663156 : }
207 :
208 842 : Timer::Timer( const Timer& rTimer ):
209 : mpTimerData(NULL),
210 : mnTimeout(rTimer.mnTimeout),
211 : mbActive(false),
212 : mbAuto(false),
213 842 : maTimeoutHdl(rTimer.maTimeoutHdl)
214 : {
215 842 : if ( rTimer.IsActive() )
216 82 : Start();
217 842 : }
218 :
219 671246 : Timer::~Timer()
220 : {
221 661188 : if ( mpTimerData )
222 : {
223 64053 : mpTimerData->mbDelete = true;
224 64053 : mpTimerData->mpTimer = NULL;
225 : }
226 671246 : }
227 :
228 46329 : void Timer::Timeout()
229 : {
230 46329 : maTimeoutHdl.Call( this );
231 46329 : }
232 :
233 808762 : void Timer::SetTimeout( sal_uLong nNewTimeout )
234 : {
235 808762 : mnTimeout = nNewTimeout;
236 :
237 : // if timer is active then renew clock
238 808762 : if ( mbActive )
239 : {
240 38011 : ImplSVData* pSVData = ImplGetSVData();
241 38011 : if ( !pSVData->mnTimerUpdate && (mnTimeout < pSVData->mnTimerPeriod) )
242 0 : ImplStartTimer( pSVData, mnTimeout );
243 : }
244 808762 : }
245 :
246 1286797 : void Timer::Start()
247 : {
248 1286797 : mbActive = true;
249 :
250 1286797 : ImplSVData* pSVData = ImplGetSVData();
251 1286797 : if ( !mpTimerData )
252 : {
253 105363 : if ( !pSVData->mpFirstTimerData )
254 : {
255 538 : pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
256 538 : if( ! pSVData->mpSalTimer )
257 : {
258 475 : pSVData->mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
259 475 : pSVData->mpSalTimer->SetCallback( ImplTimerCallbackProc );
260 : }
261 : }
262 :
263 : // insert timer and start
264 105363 : mpTimerData = new ImplTimerData;
265 105363 : mpTimerData->mpTimer = this;
266 105363 : mpTimerData->mnUpdateTime = tools::Time::GetSystemTicks();
267 105363 : mpTimerData->mnTimerUpdate = pSVData->mnTimerUpdate;
268 105363 : mpTimerData->mbDelete = false;
269 105363 : mpTimerData->mbInTimeout = false;
270 :
271 : // insert last due to SFX!
272 105363 : ImplTimerData* pPrev = NULL;
273 105363 : ImplTimerData* pData = pSVData->mpFirstTimerData;
274 2842366 : while ( pData )
275 : {
276 2631640 : pPrev = pData;
277 2631640 : pData = pData->mpNext;
278 : }
279 105363 : mpTimerData->mpNext = NULL;
280 105363 : if ( pPrev )
281 104825 : pPrev->mpNext = mpTimerData;
282 : else
283 538 : pSVData->mpFirstTimerData = mpTimerData;
284 :
285 105363 : if ( mnTimeout < pSVData->mnTimerPeriod )
286 27395 : ImplStartTimer( pSVData, mnTimeout );
287 : }
288 1181434 : else if( !mpTimerData->mpTimer ) // TODO: remove when guilty found
289 : {
290 : OSL_FAIL( "Timer::Start() on a destroyed Timer!" );
291 : }
292 : else
293 : {
294 1181434 : mpTimerData->mnUpdateTime = tools::Time::GetSystemTicks();
295 1181434 : mpTimerData->mnTimerUpdate = pSVData->mnTimerUpdate;
296 1181434 : mpTimerData->mbDelete = false;
297 : }
298 1286797 : }
299 :
300 1035423 : void Timer::Stop()
301 : {
302 1035423 : mbActive = false;
303 :
304 1035423 : if ( mpTimerData )
305 442538 : mpTimerData->mbDelete = true;
306 1035423 : }
307 :
308 98 : Timer& Timer::operator=( const Timer& rTimer )
309 : {
310 98 : if ( IsActive() )
311 26 : Stop();
312 :
313 98 : mbActive = false;
314 98 : mnTimeout = rTimer.mnTimeout;
315 98 : maTimeoutHdl = rTimer.maTimeoutHdl;
316 :
317 98 : if ( rTimer.IsActive() )
318 30 : Start();
319 :
320 98 : return *this;
321 : }
322 :
323 57035 : AutoTimer::AutoTimer()
324 : {
325 57035 : mbAuto = true;
326 57035 : }
327 :
328 842 : AutoTimer::AutoTimer( const AutoTimer& rTimer ) : Timer( rTimer )
329 : {
330 842 : mbAuto = true;
331 842 : }
332 :
333 98 : AutoTimer& AutoTimer::operator=( const AutoTimer& rTimer )
334 : {
335 98 : Timer::operator=( rTimer );
336 98 : return *this;
337 1233 : }
338 :
339 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|