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