// @(#)root/base:$Id$
// Author: Fons Rademakers   28/11/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTimer                                                               //
//                                                                      //
// Handles synchronous and a-synchronous timer events.                  //
// 1. synchronous timer is registered into TSystem and is processed     //
//    within the standard ROOT event-loop.                              //
// 2. asynchronous timer is passed to the operating system which sends  //
//    an external signal to ROOT and thus interrupts its event-loop.    //
//                                                                      //
// You can use this class in one of the following ways:                 //
//    - Sub-class TTimer and override the Notify() method.              //
//    - Re-implement the TObject::HandleTimer() method in your class    //
//      and pass a pointer to this object to timer, see the SetObject() //
//      method.                                                         //
//    - Pass an interpreter command to timer, see SetCommand() method.  //
//    - Create a TTimer, connect its Timeout() signal to the            //
//      appropriate methods. Then when the time is up it will emit a    //
//      Timeout() signal and call connected slots.                      //
//                                                                      //
//  Minimum timeout interval is defined in TSystem::ESysConstants as    //
//  kItimerResolution (currently 10 ms).                                //
//                                                                      //
//  Signal/slots example:                                               //
//       TTimer *timer = new TTimer();                                  //
//       timer->Connect("Timeout()", "myObjectClassName",               //
//                      myObject, "TimerDone()");                       //
//       timer->Start(2000, kTRUE);   // 2 seconds single-shot          //
//                                                                      //
//  To emit the Timeout signal repeadetly with minimum timeout:         //
//       timer->Start(0, kFALSE);                                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTimer.h"
#include "TSystem.h"
#include "TROOT.h"

ClassImp(TTimer)


class TSingleShotCleaner : public TTimer {
private:
   TList  *fGarbage;
public:
   TSingleShotCleaner() : TTimer(10, kTRUE) { fGarbage = new TList(); }
   virtual ~TSingleShotCleaner() { fGarbage->Delete(); delete fGarbage; }
   void TurnOn() {
      TObject *obj = (TObject*) gTQSender;
      fGarbage->Add(obj);
      Reset();
      if (gSystem)
         gSystem->AddTimer(this);
   }
   Bool_t Notify() {
      fGarbage->Delete();
      Reset();
      if (gSystem)
         gSystem->RemoveTimer(this);
      return kTRUE;
   }
};

//______________________________________________________________________________
TTimer::TTimer(Long_t ms, Bool_t mode) : fTime(ms)
{
   // Create timer that times out in ms milliseconds. If milliSec is 0
   // then the timeout will be the minimum timeout (see TSystem::ESysConstants,
   // i.e. 10 ms). If mode == kTRUE then the timer is synchronous else
   // a-synchronous. The default is synchronous. Add a timer to the system
   // eventloop by calling TurnOn(). Set command to be executed from Notify()
   // or set the object whose HandleTimer() method will be called via Notify(),
   // derive from TTimer and override Notify() or connect slots to the
   // signals Timeout(), TurnOn() and TurnOff().

   fObject      = 0;
   fCommand     = "";
   fSync        = mode;
   fIntSyscalls = kFALSE;
   Reset();
}

//______________________________________________________________________________
TTimer::TTimer(TObject *obj, Long_t ms, Bool_t mode) : fTime(ms)
{
   // Create timer that times out in ms milliseconds. If mode == kTRUE then
   // the timer is synchronous else a-synchronous. The default is synchronous.
   // Add a timer to the system eventloop by calling TurnOn().
   // The object's HandleTimer() will be called by Notify().

   fObject      = obj;
   fCommand     = "";
   fSync        = mode;
   fIntSyscalls = kFALSE;
   Reset();
}

//______________________________________________________________________________
TTimer::TTimer(const char *command, Long_t ms, Bool_t mode) : fTime(ms)
{
   // Create timer that times out in ms milliseconds. If mode == kTRUE then
   // the timer is synchronous else a-synchronous. The default is synchronous.
   // Add a timer to the system eventloop by calling TurnOn().
   // The interpreter will execute command from Notify().

   fObject      = 0;
   fCommand     = command;
   fSync        = mode;
   fIntSyscalls = kFALSE;
   Reset();
}

//______________________________________________________________________________
Bool_t TTimer::CheckTimer(const TTime &now)
{
   // Check if timer timed out.

   if (fAbsTime <= now) {
      fTimeout = kTRUE;
      Notify();
      return kTRUE;
   }
   return kFALSE;
}

//______________________________________________________________________________
Bool_t TTimer::Notify()
{
   // Notify when timer times out. The timer is always reset. To stop
   // the timer call TurnOff(). Make sure to call Reset() also in derived
   // Notify() so timers will keep working repeatedly.

   Timeout();       // emit Timeout() signal
   if (fObject) fObject->HandleTimer(this);
   if (fCommand && fCommand.Length() > 0)
      gROOT->ProcessLine(fCommand);

   Reset();
   return kTRUE;
}

//______________________________________________________________________________
void TTimer::Reset()
{
   // Reset the timer.

   // make sure gSystem exists
   ROOT::GetROOT();

   fTimeout = kFALSE;
   fAbsTime = fTime;
   if (gSystem) {
      fAbsTime += gSystem->Now();
      if (!fSync) gSystem->ResetTimer(this);
   }
}

//______________________________________________________________________________
void TTimer::SetCommand(const char *command)
{
   // Set the interpreter command to be executed at time out. Removes the
   // object to be notified (if it was set).

   fObject  = 0;
   fCommand = command;
}

//______________________________________________________________________________
void TTimer::SetObject(TObject *object)
{
   // Set the object to be notified  at time out. Removes the command to
   // be executed (if it was set).

   fObject  = object;
   fCommand = "";
}

//______________________________________________________________________________
void TTimer::SetInterruptSyscalls(Bool_t set)
{
   // When the argument is true the a-synchronous timer (SIGALRM) signal
   // handler is set so that interrupted syscalls will not be restarted
   // by the kernel. This is typically used in case one wants to put a
   // timeout on an I/O operation. By default interrupted syscalls will
   // be restarted.

   fIntSyscalls = set;
}

//___________________________________________________________________
void TTimer::Start(Long_t milliSec, Bool_t singleShot)
{
   // Starts the timer with a milliSec timeout. If milliSec is 0
   // then the timeout will be the minimum timeout (see TSystem::ESysConstants,
   // i.e. 10 ms), if milliSec is -1 then the time interval as previously
   // specified (in ctor or SetTime()) will be used.
   // If singleShot is kTRUE, the timer will be activated only once,
   // otherwise it will continue until it is stopped.
   // See also TurnOn(), Stop(), TurnOff().

   if (milliSec >= 0)
      SetTime(milliSec);
   Reset();
   TurnOn();
   if (singleShot)
      Connect(this, "Timeout()", "TTimer", this, "TurnOff()");
   else
      Disconnect(this, "Timeout()", this, "TurnOff()");
}

//______________________________________________________________________________
void TTimer::TurnOff()
{
   // Remove timer from system timer list. This requires that a timer
   // has been placed in the system timer list (using TurnOn()).
   // If a TTimer subclass is placed on another list, override TurnOff() to
   // remove the timer from the correct list.

   if (gSystem)
      if (gSystem->RemoveTimer(this))
         Emit("TurnOff()");
}

//______________________________________________________________________________
void TTimer::TurnOn()
{
   // Add the timer to the system timer list. If a TTimer subclass has to be
   // placed on another list, override TurnOn() to add the timer to the correct
   // list.

   // might have been set in a previous Start()
   Disconnect(this, "Timeout()", this, "TurnOff()");

   if (gSystem) {
      gSystem->AddTimer(this);
      Emit("TurnOn()");
   }
}

//______________________________________________________________________________
void TTimer::SingleShot(Int_t milliSec, const char *receiver_class,
                        void *receiver, const char *method)
{
   // This static function calls a slot after a given time interval.
   // Created internal timer will be deleted after that.

   TTimer *singleShotTimer = new TTimer(milliSec);
   TQObject::Connect(singleShotTimer, "Timeout()",
                     receiver_class, receiver, method);

   static TSingleShotCleaner singleShotCleaner;  // single shot timer cleaner

   // gSingleShotCleaner will delete singleShotTimer a
   // short period after Timeout() signal is emitted
   TQObject::Connect(singleShotTimer, "Timeout()",
                     "TTimer", &singleShotCleaner, "TurnOn()");

   singleShotTimer->Start(milliSec, kTRUE);
}
 TTimer.cxx:1
 TTimer.cxx:2
 TTimer.cxx:3
 TTimer.cxx:4
 TTimer.cxx:5
 TTimer.cxx:6
 TTimer.cxx:7
 TTimer.cxx:8
 TTimer.cxx:9
 TTimer.cxx:10
 TTimer.cxx:11
 TTimer.cxx:12
 TTimer.cxx:13
 TTimer.cxx:14
 TTimer.cxx:15
 TTimer.cxx:16
 TTimer.cxx:17
 TTimer.cxx:18
 TTimer.cxx:19
 TTimer.cxx:20
 TTimer.cxx:21
 TTimer.cxx:22
 TTimer.cxx:23
 TTimer.cxx:24
 TTimer.cxx:25
 TTimer.cxx:26
 TTimer.cxx:27
 TTimer.cxx:28
 TTimer.cxx:29
 TTimer.cxx:30
 TTimer.cxx:31
 TTimer.cxx:32
 TTimer.cxx:33
 TTimer.cxx:34
 TTimer.cxx:35
 TTimer.cxx:36
 TTimer.cxx:37
 TTimer.cxx:38
 TTimer.cxx:39
 TTimer.cxx:40
 TTimer.cxx:41
 TTimer.cxx:42
 TTimer.cxx:43
 TTimer.cxx:44
 TTimer.cxx:45
 TTimer.cxx:46
 TTimer.cxx:47
 TTimer.cxx:48
 TTimer.cxx:49
 TTimer.cxx:50
 TTimer.cxx:51
 TTimer.cxx:52
 TTimer.cxx:53
 TTimer.cxx:54
 TTimer.cxx:55
 TTimer.cxx:56
 TTimer.cxx:57
 TTimer.cxx:58
 TTimer.cxx:59
 TTimer.cxx:60
 TTimer.cxx:61
 TTimer.cxx:62
 TTimer.cxx:63
 TTimer.cxx:64
 TTimer.cxx:65
 TTimer.cxx:66
 TTimer.cxx:67
 TTimer.cxx:68
 TTimer.cxx:69
 TTimer.cxx:70
 TTimer.cxx:71
 TTimer.cxx:72
 TTimer.cxx:73
 TTimer.cxx:74
 TTimer.cxx:75
 TTimer.cxx:76
 TTimer.cxx:77
 TTimer.cxx:78
 TTimer.cxx:79
 TTimer.cxx:80
 TTimer.cxx:81
 TTimer.cxx:82
 TTimer.cxx:83
 TTimer.cxx:84
 TTimer.cxx:85
 TTimer.cxx:86
 TTimer.cxx:87
 TTimer.cxx:88
 TTimer.cxx:89
 TTimer.cxx:90
 TTimer.cxx:91
 TTimer.cxx:92
 TTimer.cxx:93
 TTimer.cxx:94
 TTimer.cxx:95
 TTimer.cxx:96
 TTimer.cxx:97
 TTimer.cxx:98
 TTimer.cxx:99
 TTimer.cxx:100
 TTimer.cxx:101
 TTimer.cxx:102
 TTimer.cxx:103
 TTimer.cxx:104
 TTimer.cxx:105
 TTimer.cxx:106
 TTimer.cxx:107
 TTimer.cxx:108
 TTimer.cxx:109
 TTimer.cxx:110
 TTimer.cxx:111
 TTimer.cxx:112
 TTimer.cxx:113
 TTimer.cxx:114
 TTimer.cxx:115
 TTimer.cxx:116
 TTimer.cxx:117
 TTimer.cxx:118
 TTimer.cxx:119
 TTimer.cxx:120
 TTimer.cxx:121
 TTimer.cxx:122
 TTimer.cxx:123
 TTimer.cxx:124
 TTimer.cxx:125
 TTimer.cxx:126
 TTimer.cxx:127
 TTimer.cxx:128
 TTimer.cxx:129
 TTimer.cxx:130
 TTimer.cxx:131
 TTimer.cxx:132
 TTimer.cxx:133
 TTimer.cxx:134
 TTimer.cxx:135
 TTimer.cxx:136
 TTimer.cxx:137
 TTimer.cxx:138
 TTimer.cxx:139
 TTimer.cxx:140
 TTimer.cxx:141
 TTimer.cxx:142
 TTimer.cxx:143
 TTimer.cxx:144
 TTimer.cxx:145
 TTimer.cxx:146
 TTimer.cxx:147
 TTimer.cxx:148
 TTimer.cxx:149
 TTimer.cxx:150
 TTimer.cxx:151
 TTimer.cxx:152
 TTimer.cxx:153
 TTimer.cxx:154
 TTimer.cxx:155
 TTimer.cxx:156
 TTimer.cxx:157
 TTimer.cxx:158
 TTimer.cxx:159
 TTimer.cxx:160
 TTimer.cxx:161
 TTimer.cxx:162
 TTimer.cxx:163
 TTimer.cxx:164
 TTimer.cxx:165
 TTimer.cxx:166
 TTimer.cxx:167
 TTimer.cxx:168
 TTimer.cxx:169
 TTimer.cxx:170
 TTimer.cxx:171
 TTimer.cxx:172
 TTimer.cxx:173
 TTimer.cxx:174
 TTimer.cxx:175
 TTimer.cxx:176
 TTimer.cxx:177
 TTimer.cxx:178
 TTimer.cxx:179
 TTimer.cxx:180
 TTimer.cxx:181
 TTimer.cxx:182
 TTimer.cxx:183
 TTimer.cxx:184
 TTimer.cxx:185
 TTimer.cxx:186
 TTimer.cxx:187
 TTimer.cxx:188
 TTimer.cxx:189
 TTimer.cxx:190
 TTimer.cxx:191
 TTimer.cxx:192
 TTimer.cxx:193
 TTimer.cxx:194
 TTimer.cxx:195
 TTimer.cxx:196
 TTimer.cxx:197
 TTimer.cxx:198
 TTimer.cxx:199
 TTimer.cxx:200
 TTimer.cxx:201
 TTimer.cxx:202
 TTimer.cxx:203
 TTimer.cxx:204
 TTimer.cxx:205
 TTimer.cxx:206
 TTimer.cxx:207
 TTimer.cxx:208
 TTimer.cxx:209
 TTimer.cxx:210
 TTimer.cxx:211
 TTimer.cxx:212
 TTimer.cxx:213
 TTimer.cxx:214
 TTimer.cxx:215
 TTimer.cxx:216
 TTimer.cxx:217
 TTimer.cxx:218
 TTimer.cxx:219
 TTimer.cxx:220
 TTimer.cxx:221
 TTimer.cxx:222
 TTimer.cxx:223
 TTimer.cxx:224
 TTimer.cxx:225
 TTimer.cxx:226
 TTimer.cxx:227
 TTimer.cxx:228
 TTimer.cxx:229
 TTimer.cxx:230
 TTimer.cxx:231
 TTimer.cxx:232
 TTimer.cxx:233
 TTimer.cxx:234
 TTimer.cxx:235
 TTimer.cxx:236
 TTimer.cxx:237
 TTimer.cxx:238
 TTimer.cxx:239
 TTimer.cxx:240
 TTimer.cxx:241
 TTimer.cxx:242
 TTimer.cxx:243
 TTimer.cxx:244
 TTimer.cxx:245
 TTimer.cxx:246
 TTimer.cxx:247
 TTimer.cxx:248
 TTimer.cxx:249
 TTimer.cxx:250
 TTimer.cxx:251
 TTimer.cxx:252
 TTimer.cxx:253
 TTimer.cxx:254
 TTimer.cxx:255
 TTimer.cxx:256
 TTimer.cxx:257
 TTimer.cxx:258
 TTimer.cxx:259
 TTimer.cxx:260
 TTimer.cxx:261
 TTimer.cxx:262
 TTimer.cxx:263
 TTimer.cxx:264
 TTimer.cxx:265
 TTimer.cxx:266
 TTimer.cxx:267
 TTimer.cxx:268
 TTimer.cxx:269
 TTimer.cxx:270