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