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 1 : void Timer::ImplDeInitTimer()
42 : {
43 1 : ImplSVData* pSVData = ImplGetSVData();
44 1 : ImplTimerData* pTimerData = pSVData->mpFirstTimerData;
45 :
46 1 : if ( pTimerData )
47 : {
48 0 : do
49 : {
50 0 : ImplTimerData* pTempTimerData = pTimerData;
51 0 : if ( pTimerData->mpTimer )
52 : {
53 0 : pTimerData->mpTimer->mbActive = false;
54 0 : pTimerData->mpTimer->mpTimerData = NULL;
55 : }
56 0 : pTimerData = pTimerData->mpNext;
57 0 : delete pTempTimerData;
58 : }
59 : while ( pTimerData );
60 :
61 0 : pSVData->mpFirstTimerData = NULL;
62 0 : pSVData->mnTimerPeriod = 0;
63 0 : delete pSVData->mpSalTimer;
64 0 : pSVData->mpSalTimer = NULL;
65 : }
66 1 : }
67 :
68 0 : static void ImplStartTimer( ImplSVData* pSVData, sal_uLong nMS )
69 : {
70 0 : if ( !nMS )
71 0 : nMS = 1;
72 :
73 0 : if ( nMS != pSVData->mnTimerPeriod )
74 : {
75 0 : pSVData->mnTimerPeriod = nMS;
76 0 : pSVData->mpSalTimer->Start( nMS );
77 : }
78 0 : }
79 :
80 0 : void Timer::ImplTimerCallbackProc()
81 : {
82 0 : ImplSVData* pSVData = ImplGetSVData();
83 : ImplTimerData* pTimerData;
84 : ImplTimerData* pPrevTimerData;
85 0 : sal_uLong nMinPeriod = MAX_TIMER_PERIOD;
86 : sal_uLong nDeltaTime;
87 0 : sal_uLong nTime = Time::GetSystemTicks();
88 :
89 0 : if ( pSVData->mbNoCallTimer )
90 0 : return;
91 :
92 0 : pSVData->mnTimerUpdate++;
93 0 : pSVData->mbNotAllTimerCalled = true;
94 :
95 : // find timer where the timer handler needs to be called
96 0 : pTimerData = pSVData->mpFirstTimerData;
97 0 : while ( pTimerData )
98 : {
99 : // If the timer is not new, was not deleted, and if it is not in the timeout handler, then
100 : // call the handler as soon as the time is up.
101 0 : if ( (pTimerData->mnTimerUpdate < pSVData->mnTimerUpdate) &&
102 0 : !pTimerData->mbDelete && !pTimerData->mbInTimeout )
103 : {
104 : // time has expired
105 0 : if ( (pTimerData->mnUpdateTime+pTimerData->mpTimer->mnTimeout) <= nTime )
106 : {
107 : // set new update time
108 0 : pTimerData->mnUpdateTime = nTime;
109 :
110 : // if no AutoTimer than stop
111 0 : if ( !pTimerData->mpTimer->mbAuto )
112 : {
113 0 : pTimerData->mpTimer->mbActive = false;
114 0 : pTimerData->mbDelete = true;
115 : }
116 :
117 : // call Timeout
118 0 : pTimerData->mbInTimeout = true;
119 0 : pTimerData->mpTimer->Timeout();
120 0 : pTimerData->mbInTimeout = false;
121 : }
122 : }
123 :
124 0 : pTimerData = pTimerData->mpNext;
125 : }
126 :
127 : // determine new time
128 0 : sal_uLong nNewTime = Time::GetSystemTicks();
129 0 : pPrevTimerData = NULL;
130 0 : pTimerData = pSVData->mpFirstTimerData;
131 0 : while ( pTimerData )
132 : {
133 : // ignore if timer is still in timeout handler
134 0 : if ( pTimerData->mbInTimeout )
135 : {
136 0 : pPrevTimerData = pTimerData;
137 0 : pTimerData = pTimerData->mpNext;
138 : }
139 : // Was timer destroyed in the meantime?
140 0 : else if ( pTimerData->mbDelete )
141 : {
142 0 : if ( pPrevTimerData )
143 0 : pPrevTimerData->mpNext = pTimerData->mpNext;
144 : else
145 0 : pSVData->mpFirstTimerData = pTimerData->mpNext;
146 0 : if ( pTimerData->mpTimer )
147 0 : pTimerData->mpTimer->mpTimerData = NULL;
148 0 : ImplTimerData* pTempTimerData = pTimerData;
149 0 : pTimerData = pTimerData->mpNext;
150 0 : delete pTempTimerData;
151 : }
152 : else
153 : {
154 0 : pTimerData->mnTimerUpdate = 0;
155 : // determine smallest time slot
156 0 : if ( pTimerData->mnUpdateTime == nTime )
157 : {
158 0 : nDeltaTime = pTimerData->mpTimer->mnTimeout;
159 0 : if ( nDeltaTime < nMinPeriod )
160 0 : nMinPeriod = nDeltaTime;
161 : }
162 : else
163 : {
164 0 : nDeltaTime = pTimerData->mnUpdateTime + pTimerData->mpTimer->mnTimeout;
165 0 : if ( nDeltaTime < nNewTime )
166 0 : nMinPeriod = 1;
167 : else
168 : {
169 0 : nDeltaTime -= nNewTime;
170 0 : if ( nDeltaTime < nMinPeriod )
171 0 : nMinPeriod = nDeltaTime;
172 : }
173 : }
174 0 : pPrevTimerData = pTimerData;
175 0 : pTimerData = pTimerData->mpNext;
176 : }
177 : }
178 :
179 : // delete clock if no more timers available
180 0 : if ( !pSVData->mpFirstTimerData )
181 : {
182 0 : pSVData->mpSalTimer->Stop();
183 0 : pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
184 : }
185 : else
186 0 : ImplStartTimer( pSVData, nMinPeriod );
187 :
188 0 : pSVData->mnTimerUpdate--;
189 0 : pSVData->mbNotAllTimerCalled = false;
190 : }
191 :
192 1 : Timer::Timer():
193 : mpTimerData(NULL),
194 : mnTimeout(1),
195 : mbActive(false),
196 1 : mbAuto(false)
197 : {
198 1 : }
199 :
200 0 : Timer::Timer( const Timer& rTimer ):
201 : mpTimerData(NULL),
202 : mnTimeout(rTimer.mnTimeout),
203 : mbActive(false),
204 : mbAuto(false),
205 0 : maTimeoutHdl(rTimer.maTimeoutHdl)
206 : {
207 0 : if ( rTimer.IsActive() )
208 0 : Start();
209 0 : }
210 :
211 1 : Timer::~Timer()
212 : {
213 1 : if ( mpTimerData )
214 : {
215 0 : mpTimerData->mbDelete = true;
216 0 : mpTimerData->mpTimer = NULL;
217 : }
218 1 : }
219 :
220 0 : void Timer::Timeout()
221 : {
222 0 : maTimeoutHdl.Call( this );
223 0 : }
224 :
225 0 : void Timer::SetTimeout( sal_uLong nNewTimeout )
226 : {
227 0 : mnTimeout = nNewTimeout;
228 :
229 : // if timer is active then renew clock
230 0 : if ( mbActive )
231 : {
232 0 : ImplSVData* pSVData = ImplGetSVData();
233 0 : if ( !pSVData->mnTimerUpdate && (mnTimeout < pSVData->mnTimerPeriod) )
234 0 : ImplStartTimer( pSVData, mnTimeout );
235 : }
236 0 : }
237 :
238 0 : void Timer::Start()
239 : {
240 0 : mbActive = true;
241 :
242 0 : ImplSVData* pSVData = ImplGetSVData();
243 0 : if ( !mpTimerData )
244 : {
245 0 : if ( !pSVData->mpFirstTimerData )
246 : {
247 0 : pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
248 0 : if( ! pSVData->mpSalTimer )
249 : {
250 0 : pSVData->mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
251 0 : pSVData->mpSalTimer->SetCallback( ImplTimerCallbackProc );
252 : }
253 : }
254 :
255 : // insert timer and start
256 0 : mpTimerData = new ImplTimerData;
257 0 : mpTimerData->mpTimer = this;
258 0 : mpTimerData->mnUpdateTime = Time::GetSystemTicks();
259 0 : mpTimerData->mnTimerUpdate = pSVData->mnTimerUpdate;
260 0 : mpTimerData->mbDelete = false;
261 0 : mpTimerData->mbInTimeout = false;
262 :
263 : // insert last due to SFX!
264 0 : ImplTimerData* pPrev = NULL;
265 0 : ImplTimerData* pData = pSVData->mpFirstTimerData;
266 0 : while ( pData )
267 : {
268 0 : pPrev = pData;
269 0 : pData = pData->mpNext;
270 : }
271 0 : mpTimerData->mpNext = NULL;
272 0 : if ( pPrev )
273 0 : pPrev->mpNext = mpTimerData;
274 : else
275 0 : pSVData->mpFirstTimerData = mpTimerData;
276 :
277 0 : if ( mnTimeout < pSVData->mnTimerPeriod )
278 0 : ImplStartTimer( pSVData, mnTimeout );
279 : }
280 0 : else if( !mpTimerData->mpTimer ) // TODO: remove when guilty found
281 : {
282 : OSL_FAIL( "Timer::Start() on a destroyed Timer!" );
283 : }
284 : else
285 : {
286 0 : mpTimerData->mnUpdateTime = Time::GetSystemTicks();
287 0 : mpTimerData->mnTimerUpdate = pSVData->mnTimerUpdate;
288 0 : mpTimerData->mbDelete = false;
289 : }
290 0 : }
291 :
292 0 : void Timer::Stop()
293 : {
294 0 : mbActive = false;
295 :
296 0 : if ( mpTimerData )
297 0 : mpTimerData->mbDelete = true;
298 0 : }
299 :
300 0 : Timer& Timer::operator=( const Timer& rTimer )
301 : {
302 0 : if ( IsActive() )
303 0 : Stop();
304 :
305 0 : mbActive = false;
306 0 : mnTimeout = rTimer.mnTimeout;
307 0 : maTimeoutHdl = rTimer.maTimeoutHdl;
308 :
309 0 : if ( rTimer.IsActive() )
310 0 : Start();
311 :
312 0 : return *this;
313 : }
314 :
315 0 : AutoTimer::AutoTimer()
316 : {
317 0 : mbAuto = true;
318 0 : }
319 :
320 0 : AutoTimer::AutoTimer( const AutoTimer& rTimer ) : Timer( rTimer )
321 : {
322 0 : mbAuto = true;
323 0 : }
324 :
325 0 : AutoTimer& AutoTimer::operator=( const AutoTimer& rTimer )
326 : {
327 0 : Timer::operator=( rTimer );
328 0 : return *this;
329 : }
330 :
331 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|