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