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