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 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 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 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 216 Timer::Timer() 217 { 218 mpTimerData = NULL; 219 mnTimeout = 1; 220 mbAuto = sal_False; 221 mbActive = sal_False; 222 } 223 224 // ----------------------------------------------------------------------- 225 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 240 Timer::~Timer() 241 { 242 if ( mpTimerData ) 243 { 244 mpTimerData->mbDelete = sal_True; 245 mpTimerData->mpSVTimer = NULL; 246 } 247 } 248 249 // ----------------------------------------------------------------------- 250 251 void Timer::Timeout() 252 { 253 maTimeoutHdl.Call( this ); 254 } 255 256 // ----------------------------------------------------------------------- 257 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 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 329 void Timer::Stop() 330 { 331 mbActive = sal_False; 332 333 if ( mpTimerData ) 334 mpTimerData->mbDelete = sal_True; 335 } 336 337 // ----------------------------------------------------------------------- 338 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 356 AutoTimer::AutoTimer() 357 { 358 mbAuto = sal_True; 359 } 360 361 // ----------------------------------------------------------------------- 362 363 AutoTimer::AutoTimer( const AutoTimer& rTimer ) : Timer( rTimer ) 364 { 365 mbAuto = sal_True; 366 } 367 368 // ----------------------------------------------------------------------- 369 370 AutoTimer& AutoTimer::operator=( const AutoTimer& rTimer ) 371 { 372 Timer::operator=( rTimer ); 373 return *this; 374 } 375