]> git.mxchange.org Git - simgear.git/blobdiff - simgear/structure/event_mgr.cxx
Improve (mostly Canvas event related) documentation.
[simgear.git] / simgear / structure / event_mgr.cxx
index 32c499f9988961dabc906ee5900cb507a371ad22..503bd974e7f9c551604c958787e5d191a9b09d0a 100644 (file)
+#ifdef HAVE_CONFIG_H
+#  include <simgear_config.h>
+#endif
+
 #include "event_mgr.hxx"
 
-void SGEventMgr::add(SGCallback* cb,
+#include <simgear/debug/logstream.hxx>
+
+void SGEventMgr::add(const std::string& name, SGCallback* cb,
                      double interval, double delay,
                      bool repeat, bool simtime)
 {
+    // Clamp the delay value to 1 usec, so that user code can use
+    // "zero" as a synonym for "next frame".
+    if(delay <= 0) delay = 1e-6;
+    if(interval <= 0) interval = 1e-6; // No timer endless loops please...
+
     SGTimer* t = new SGTimer;
     t->interval = interval;
     t->callback = cb;
-    t->mgr = this;
     t->repeat = repeat;
-    t->simtime = simtime;
-
+    t->name = name;
+    t->running = false;
+    
     SGTimerQueue* q = simtime ? &_simQueue : &_rtQueue;
 
     q->insert(t, delay);
 }
 
+SGTimer::~SGTimer()
+{
+    delete callback;
+    callback = NULL;
+}
+
 void SGTimer::run()
 {
     (*callback)();
+}
+
+SGEventMgr::SGEventMgr() :
+    _inited(false)
+{
+    
+}
+
+SGEventMgr::~SGEventMgr()
+{
+    
+}
+
+void SGEventMgr::unbind()
+{
+    _freezeProp.clear();
+    _rtProp.clear();
+}
 
-    if(repeat) {
-        SGTimerQueue* q = simtime ? &mgr->_simQueue : &mgr->_rtQueue;
-        q->insert(this, interval);
-    } else {
-        delete callback;
-        delete this;
+void SGEventMgr::init()
+{
+    if (_inited) {
+        SG_LOG(SG_GENERAL, SG_WARN, "duplicate init of SGEventMgr");
     }
+    _inited = true;
+}
+
+void SGEventMgr::shutdown()
+{
+    _inited = false;
+    
+    _simQueue.clear();
+    _rtQueue.clear();
 }
 
 void SGEventMgr::update(double delta_time_sec)
 {
-    _rtQueue.update(delta_time_sec);
-    if(!_freezeProp || _freezeProp->getBoolValue() == false)
-        _simQueue.update(delta_time_sec);
+    _simQueue.update(delta_time_sec);
+    
+    double rt = _rtProp ? _rtProp->getDoubleValue() : 0;
+    _rtQueue.update(rt);
+}
+
+void SGEventMgr::removeTask(const std::string& name)
+{
+    // due to the ordering of the event-mgr in FG, tasks can be removed
+    // after we are shutdown (and hence, have all been cleared). Guard
+    // against this so we don't generate warnings below.
+    if (!_inited) {
+        return;
+    }
+    
+  SGTimer* t = _simQueue.findByName(name);
+  if (t) {
+    _simQueue.remove(t);
+  } else if ((t = _rtQueue.findByName(name))) {
+    _rtQueue.remove(t);
+  } else {
+    SG_LOG(SG_GENERAL, SG_WARN, "removeTask: no task found with name:" << name);
+    return;
+  }
+  if (t->running) {
+    // mark as not repeating so that the SGTimerQueue::update()
+    // will clean it up
+    t->repeat = false;
+  } else {
+    delete t;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////
@@ -51,7 +121,7 @@ SGTimerQueue::SGTimerQueue(int size)
 
     _table = new HeapEntry[_tableSize];
     for(int i=0; i<_tableSize; i++) {
-       _table[i].pri = 0;
+           _table[i].pri = 0;
         _table[i].timer = 0;
     }
 }
@@ -59,22 +129,45 @@ SGTimerQueue::SGTimerQueue(int size)
 
 SGTimerQueue::~SGTimerQueue()
 {
+    clear();
     delete[] _table;
 }
 
+void SGTimerQueue::clear()
+{
+    // delete entries
+    for(int i=0; i<_numEntries; i++) {
+        delete _table[i].timer;
+    }
+    
+    _numEntries = 0;
+    
+    // clear entire table to empty
+    for(int i=0; i<_tableSize; i++) {
+           _table[i].pri = 0;
+        _table[i].timer = 0;
+    }
+}
+
 void SGTimerQueue::update(double deltaSecs)
 {
     _now += deltaSecs;
     while(_numEntries && nextTime() <= _now) {
         SGTimer* t = remove();
+        if(t->repeat)
+            insert(t, t->interval);
+        // warning: this is not thread safe
+        // but the entire timer queue isn't either
+        t->running = true;
         t->run();
+        t->running = false;
+        if (!t->repeat)
+            delete t;
     }
 }
 
 void SGTimerQueue::insert(SGTimer* timer, double time)
 {
-    if(time < 0) *(int*)0=0;
-
     if(_numEntries >= _tableSize)
        growArray();
 
@@ -120,21 +213,16 @@ SGTimer* SGTimerQueue::remove()
 
 void SGTimerQueue::siftDown(int n)
 {
-    // While we have a child bigger than us:
-    while(((lchild(n) < (_numEntries-1))
-          && (_table[n].pri < _table[lchild(n)].pri))
-         ||
-         ((rchild(n) < (_numEntries-1))
-          && (_table[n].pri < _table[rchild(n)].pri)))
-    {
-        // Swap us with the biggest child
-        if(_table[lchild(n)].pri > _table[rchild(n)].pri) {
-            swap(n, lchild(n)); 
-            n = lchild(n);
-        } else {
-            swap(n, rchild(n));
-            n = rchild(n);
-        }
+    // While we have children bigger than us, swap us with the biggest
+    // child.
+    while(lchild(n) < _numEntries) {
+        int bigc = lchild(n);
+        if(rchild(n) < _numEntries && pri(rchild(n)) > pri(bigc))
+            bigc = rchild(n);
+        if(pri(bigc) <= pri(n))
+            break;
+        swap(n, bigc);
+        n = bigc;
     }
 }
 
@@ -158,3 +246,14 @@ void SGTimerQueue::growArray()
     delete[] _table;
     _table = newTable;
 }
+
+SGTimer* SGTimerQueue::findByName(const std::string& name) const
+{
+  for (int i=0; i < _numEntries; ++i) {
+    if (_table[i].timer->name == name) {
+      return _table[i].timer;
+    }
+  }
+  
+  return NULL;
+}