xref: /trunk/main/vcl/source/app/timer.cxx (revision 9f62ea84)
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