1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26
27 #include <tools/time.hxx>
28 #include <tools/debug.hxx>
29
30 #include <vcl/svapp.hxx>
31 #include <vcl/timer.hxx>
32
33 #include <saltimer.hxx>
34 #include <svdata.hxx>
35 #include <salinst.hxx>
36
37
38 // =======================================================================
39
40 #define MAX_TIMER_PERIOD ((sal_uLong)0xFFFFFFFF)
41
42 // ---------------------
43 // - TimeManager-Types -
44 // ---------------------
45
46 struct ImplTimerData
47 {
48 ImplTimerData* mpNext; // Pointer to the next Instance
49 Timer* mpSVTimer; // Pointer to SV Timer instance
50 sal_uLong mnUpdateTime; // Last Update Time
51 sal_uLong mnTimerUpdate; // TimerCallbackProcs on stack
52 sal_Bool mbDelete; // Wurde Timer waehren Update() geloescht
53 sal_Bool mbInTimeout; // Befinden wir uns im Timeout-Handler
54 };
55
56 // =======================================================================
57
ImplDeInitTimer()58 void Timer::ImplDeInitTimer()
59 {
60 ImplSVData* pSVData = ImplGetSVData();
61 ImplTimerData* pTimerData = pSVData->mpFirstTimerData;
62
63 if ( pTimerData )
64 {
65 do
66 {
67 ImplTimerData* pTempTimerData = pTimerData;
68 if ( pTimerData->mpSVTimer )
69 {
70 pTimerData->mpSVTimer->mbActive = sal_False;
71 pTimerData->mpSVTimer->mpTimerData = NULL;
72 }
73 pTimerData = pTimerData->mpNext;
74 delete pTempTimerData;
75 }
76 while ( pTimerData );
77
78 pSVData->mpFirstTimerData = NULL;
79 pSVData->mnTimerPeriod = 0;
80 delete pSVData->mpSalTimer;
81 pSVData->mpSalTimer = NULL;
82 }
83 }
84
85 // -----------------------------------------------------------------------
86
ImplStartTimer(ImplSVData * pSVData,sal_uLong nMS)87 static void ImplStartTimer( ImplSVData* pSVData, sal_uLong nMS )
88 {
89 if ( !nMS )
90 nMS = 1;
91
92 if ( nMS != pSVData->mnTimerPeriod )
93 {
94 pSVData->mnTimerPeriod = nMS;
95 pSVData->mpSalTimer->Start( nMS );
96 }
97 }
98
99 // -----------------------------------------------------------------------
100
ImplTimerCallbackProc()101 void Timer::ImplTimerCallbackProc()
102 {
103 ImplSVData* pSVData = ImplGetSVData();
104 ImplTimerData* pTimerData;
105 ImplTimerData* pPrevTimerData;
106 sal_uLong nMinPeriod = MAX_TIMER_PERIOD;
107 sal_uLong nDeltaTime;
108 sal_uLong nTime = Time::GetSystemTicks();
109
110 if ( pSVData->mbNoCallTimer )
111 return;
112
113 pSVData->mnTimerUpdate++;
114 pSVData->mbNotAllTimerCalled = sal_True;
115
116 // Suche Timer raus, wo der Timeout-Handler gerufen werden muss
117 pTimerData = pSVData->mpFirstTimerData;
118 while ( pTimerData )
119 {
120 // Wenn Timer noch nicht neu ist und noch nicht geloescht wurde
121 // und er sich nicht im Timeout-Handler befindet,
122 // dann den Handler rufen, wenn die Zeit abgelaufen ist
123 if ( (pTimerData->mnTimerUpdate < pSVData->mnTimerUpdate) &&
124 !pTimerData->mbDelete && !pTimerData->mbInTimeout )
125 {
126 // Zeit abgelaufen
127 if ( (pTimerData->mnUpdateTime+pTimerData->mpSVTimer->mnTimeout) <= nTime )
128 {
129 // Neue Updatezeit setzen
130 pTimerData->mnUpdateTime = nTime;
131
132 // kein AutoTimer, dann anhalten
133 if ( !pTimerData->mpSVTimer->mbAuto )
134 {
135 pTimerData->mpSVTimer->mbActive = sal_False;
136 pTimerData->mbDelete = sal_True;
137 }
138
139 // call Timeout
140 pTimerData->mbInTimeout = sal_True;
141 pTimerData->mpSVTimer->Timeout();
142 pTimerData->mbInTimeout = sal_False;
143 }
144 }
145
146 pTimerData = pTimerData->mpNext;
147 }
148
149 // Neue Zeit ermitteln
150 sal_uLong nNewTime = Time::GetSystemTicks();
151 pPrevTimerData = NULL;
152 pTimerData = pSVData->mpFirstTimerData;
153 while ( pTimerData )
154 {
155 // Befindet sich Timer noch im Timeout-Handler, dann ignorieren
156 if ( pTimerData->mbInTimeout )
157 {
158 pPrevTimerData = pTimerData;
159 pTimerData = pTimerData->mpNext;
160 }
161 // Wurde Timer zwischenzeitlich zerstoert ?
162 else if ( pTimerData->mbDelete )
163 {
164 if ( pPrevTimerData )
165 pPrevTimerData->mpNext = pTimerData->mpNext;
166 else
167 pSVData->mpFirstTimerData = pTimerData->mpNext;
168 if ( pTimerData->mpSVTimer )
169 pTimerData->mpSVTimer->mpTimerData = NULL;
170 ImplTimerData* pTempTimerData = pTimerData;
171 pTimerData = pTimerData->mpNext;
172 delete pTempTimerData;
173 }
174 else
175 {
176 pTimerData->mnTimerUpdate = 0;
177 // kleinste Zeitspanne ermitteln
178 if ( pTimerData->mnUpdateTime == nTime )
179 {
180 nDeltaTime = pTimerData->mpSVTimer->mnTimeout;
181 if ( nDeltaTime < nMinPeriod )
182 nMinPeriod = nDeltaTime;
183 }
184 else
185 {
186 nDeltaTime = pTimerData->mnUpdateTime + pTimerData->mpSVTimer->mnTimeout;
187 if ( nDeltaTime < nNewTime )
188 nMinPeriod = 1;
189 else
190 {
191 nDeltaTime -= nNewTime;
192 if ( nDeltaTime < nMinPeriod )
193 nMinPeriod = nDeltaTime;
194 }
195 }
196 pPrevTimerData = pTimerData;
197 pTimerData = pTimerData->mpNext;
198 }
199 }
200
201 // Wenn keine Timer mehr existieren, dann Clock loeschen
202 if ( !pSVData->mpFirstTimerData )
203 {
204 pSVData->mpSalTimer->Stop();
205 pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
206 }
207 else
208 ImplStartTimer( pSVData, nMinPeriod );
209
210 pSVData->mnTimerUpdate--;
211 pSVData->mbNotAllTimerCalled = sal_False;
212 }
213
214 // =======================================================================
215
Timer()216 Timer::Timer()
217 {
218 mpTimerData = NULL;
219 mnTimeout = 1;
220 mbAuto = sal_False;
221 mbActive = sal_False;
222 }
223
224 // -----------------------------------------------------------------------
225
Timer(const Timer & rTimer)226 Timer::Timer( const Timer& rTimer )
227 {
228 mpTimerData = NULL;
229 mnTimeout = rTimer.mnTimeout;
230 mbAuto = sal_False;
231 mbActive = sal_False;
232 maTimeoutHdl = rTimer.maTimeoutHdl;
233
234 if ( rTimer.IsActive() )
235 Start();
236 }
237
238 // -----------------------------------------------------------------------
239
~Timer()240 Timer::~Timer()
241 {
242 if ( mpTimerData )
243 {
244 mpTimerData->mbDelete = sal_True;
245 mpTimerData->mpSVTimer = NULL;
246 }
247 }
248
249 // -----------------------------------------------------------------------
250
Timeout()251 void Timer::Timeout()
252 {
253 maTimeoutHdl.Call( this );
254 }
255
256 // -----------------------------------------------------------------------
257
SetTimeout(sal_uLong nNewTimeout)258 void Timer::SetTimeout( sal_uLong nNewTimeout )
259 {
260 mnTimeout = nNewTimeout;
261
262 // Wenn Timer aktiv, dann Clock erneuern
263 if ( mbActive )
264 {
265 ImplSVData* pSVData = ImplGetSVData();
266 if ( !pSVData->mnTimerUpdate && (mnTimeout < pSVData->mnTimerPeriod) )
267 ImplStartTimer( pSVData, mnTimeout );
268 }
269 }
270
271 // -----------------------------------------------------------------------
272
Start()273 void Timer::Start()
274 {
275 mbActive = sal_True;
276
277 ImplSVData* pSVData = ImplGetSVData();
278 if ( !mpTimerData )
279 {
280 if ( !pSVData->mpFirstTimerData )
281 {
282 pSVData->mnTimerPeriod = MAX_TIMER_PERIOD;
283 if( ! pSVData->mpSalTimer )
284 {
285 pSVData->mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
286 pSVData->mpSalTimer->SetCallback( ImplTimerCallbackProc );
287 }
288 }
289
290 // insert timer and start
291 mpTimerData = new ImplTimerData;
292 mpTimerData->mpSVTimer = this;
293 mpTimerData->mnUpdateTime = Time::GetSystemTicks();
294 mpTimerData->mnTimerUpdate = pSVData->mnTimerUpdate;
295 mpTimerData->mbDelete = sal_False;
296 mpTimerData->mbInTimeout = sal_False;
297
298 // !!!!! Wegen SFX hinten einordnen !!!!!
299 ImplTimerData* pPrev = NULL;
300 ImplTimerData* pData = pSVData->mpFirstTimerData;
301 while ( pData )
302 {
303 pPrev = pData;
304 pData = pData->mpNext;
305 }
306 mpTimerData->mpNext = NULL;
307 if ( pPrev )
308 pPrev->mpNext = mpTimerData;
309 else
310 pSVData->mpFirstTimerData = mpTimerData;
311
312 if ( mnTimeout < pSVData->mnTimerPeriod )
313 ImplStartTimer( pSVData, mnTimeout );
314 }
315 else if( !mpTimerData->mpSVTimer ) // TODO: remove when guilty found
316 {
317 DBG_ERROR( "Timer::Start() on a destroyed Timer!" );
318 }
319 else
320 {
321 mpTimerData->mnUpdateTime = Time::GetSystemTicks();
322 mpTimerData->mnTimerUpdate = pSVData->mnTimerUpdate;
323 mpTimerData->mbDelete = sal_False;
324 }
325 }
326
327 // -----------------------------------------------------------------------
328
Stop()329 void Timer::Stop()
330 {
331 mbActive = sal_False;
332
333 if ( mpTimerData )
334 mpTimerData->mbDelete = sal_True;
335 }
336
337 // -----------------------------------------------------------------------
338
operator =(const Timer & rTimer)339 Timer& Timer::operator=( const Timer& rTimer )
340 {
341 if ( IsActive() )
342 Stop();
343
344 mbActive = sal_False;
345 mnTimeout = rTimer.mnTimeout;
346 maTimeoutHdl = rTimer.maTimeoutHdl;
347
348 if ( rTimer.IsActive() )
349 Start();
350
351 return *this;
352 }
353
354 // =======================================================================
355
AutoTimer()356 AutoTimer::AutoTimer()
357 {
358 mbAuto = sal_True;
359 }
360
361 // -----------------------------------------------------------------------
362
AutoTimer(const AutoTimer & rTimer)363 AutoTimer::AutoTimer( const AutoTimer& rTimer ) : Timer( rTimer )
364 {
365 mbAuto = sal_True;
366 }
367
368 // -----------------------------------------------------------------------
369
operator =(const AutoTimer & rTimer)370 AutoTimer& AutoTimer::operator=( const AutoTimer& rTimer )
371 {
372 Timer::operator=( rTimer );
373 return *this;
374 }
375