]> git.mxchange.org Git - simgear.git/blob - simgear/structure/event_mgr.cxx
Improve (mostly Canvas event related) documentation.
[simgear.git] / simgear / structure / event_mgr.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <simgear_config.h>
3 #endif
4
5 #include "event_mgr.hxx"
6
7 #include <simgear/debug/logstream.hxx>
8
9 void SGEventMgr::add(const std::string& name, SGCallback* cb,
10                      double interval, double delay,
11                      bool repeat, bool simtime)
12 {
13     // Clamp the delay value to 1 usec, so that user code can use
14     // "zero" as a synonym for "next frame".
15     if(delay <= 0) delay = 1e-6;
16     if(interval <= 0) interval = 1e-6; // No timer endless loops please...
17
18     SGTimer* t = new SGTimer;
19     t->interval = interval;
20     t->callback = cb;
21     t->repeat = repeat;
22     t->name = name;
23     t->running = false;
24     
25     SGTimerQueue* q = simtime ? &_simQueue : &_rtQueue;
26
27     q->insert(t, delay);
28 }
29
30 SGTimer::~SGTimer()
31 {
32     delete callback;
33     callback = NULL;
34 }
35
36 void SGTimer::run()
37 {
38     (*callback)();
39 }
40
41 SGEventMgr::SGEventMgr() :
42     _inited(false)
43 {
44     
45 }
46
47 SGEventMgr::~SGEventMgr()
48 {
49     
50 }
51
52 void SGEventMgr::unbind()
53 {
54     _freezeProp.clear();
55     _rtProp.clear();
56 }
57
58 void SGEventMgr::init()
59 {
60     if (_inited) {
61         SG_LOG(SG_GENERAL, SG_WARN, "duplicate init of SGEventMgr");
62     }
63     _inited = true;
64 }
65
66 void SGEventMgr::shutdown()
67 {
68     _inited = false;
69     
70     _simQueue.clear();
71     _rtQueue.clear();
72 }
73
74 void SGEventMgr::update(double delta_time_sec)
75 {
76     _simQueue.update(delta_time_sec);
77     
78     double rt = _rtProp ? _rtProp->getDoubleValue() : 0;
79     _rtQueue.update(rt);
80 }
81
82 void SGEventMgr::removeTask(const std::string& name)
83 {
84     // due to the ordering of the event-mgr in FG, tasks can be removed
85     // after we are shutdown (and hence, have all been cleared). Guard
86     // against this so we don't generate warnings below.
87     if (!_inited) {
88         return;
89     }
90     
91   SGTimer* t = _simQueue.findByName(name);
92   if (t) {
93     _simQueue.remove(t);
94   } else if ((t = _rtQueue.findByName(name))) {
95     _rtQueue.remove(t);
96   } else {
97     SG_LOG(SG_GENERAL, SG_WARN, "removeTask: no task found with name:" << name);
98     return;
99   }
100   if (t->running) {
101     // mark as not repeating so that the SGTimerQueue::update()
102     // will clean it up
103     t->repeat = false;
104   } else {
105     delete t;
106   }
107 }
108
109 ////////////////////////////////////////////////////////////////////////
110 // SGTimerQueue
111 // This is the priority queue implementation:
112 ////////////////////////////////////////////////////////////////////////
113
114 SGTimerQueue::SGTimerQueue(int size)
115 {
116     _now = 0;
117     _numEntries = 0;
118     _tableSize = 1;
119     while(size > _tableSize)
120         _tableSize = ((_tableSize + 1)<<1) - 1;
121
122     _table = new HeapEntry[_tableSize];
123     for(int i=0; i<_tableSize; i++) {
124             _table[i].pri = 0;
125         _table[i].timer = 0;
126     }
127 }
128
129
130 SGTimerQueue::~SGTimerQueue()
131 {
132     clear();
133     delete[] _table;
134 }
135
136 void SGTimerQueue::clear()
137 {
138     // delete entries
139     for(int i=0; i<_numEntries; i++) {
140         delete _table[i].timer;
141     }
142     
143     _numEntries = 0;
144     
145     // clear entire table to empty
146     for(int i=0; i<_tableSize; i++) {
147             _table[i].pri = 0;
148         _table[i].timer = 0;
149     }
150 }
151
152 void SGTimerQueue::update(double deltaSecs)
153 {
154     _now += deltaSecs;
155     while(_numEntries && nextTime() <= _now) {
156         SGTimer* t = remove();
157         if(t->repeat)
158             insert(t, t->interval);
159         // warning: this is not thread safe
160         // but the entire timer queue isn't either
161         t->running = true;
162         t->run();
163         t->running = false;
164         if (!t->repeat)
165             delete t;
166     }
167 }
168
169 void SGTimerQueue::insert(SGTimer* timer, double time)
170 {
171     if(_numEntries >= _tableSize)
172         growArray();
173
174     _numEntries++;
175     _table[_numEntries-1].pri = -(_now + time);
176     _table[_numEntries-1].timer = timer;
177
178     siftUp(_numEntries-1);
179 }
180
181 SGTimer* SGTimerQueue::remove(SGTimer* t)
182 {
183     int entry;
184     for(entry=0; entry<_numEntries; entry++)
185         if(_table[entry].timer == t)
186             break;
187     if(entry == _numEntries)
188         return 0;
189
190     // Swap in the last item in the table, and sift down
191     swap(entry, _numEntries-1);
192     _numEntries--;
193     siftDown(entry);
194
195     return t;
196 }
197
198 SGTimer* SGTimerQueue::remove()
199 {
200     if(_numEntries == 0) {
201         return 0;
202     } else if(_numEntries == 1) {
203         _numEntries = 0;
204         return _table[0].timer;
205     }
206
207     SGTimer *result = _table[0].timer;
208     _table[0] = _table[_numEntries - 1];
209     _numEntries--;
210     siftDown(0);
211     return result;
212 }
213
214 void SGTimerQueue::siftDown(int n)
215 {
216     // While we have children bigger than us, swap us with the biggest
217     // child.
218     while(lchild(n) < _numEntries) {
219         int bigc = lchild(n);
220         if(rchild(n) < _numEntries && pri(rchild(n)) > pri(bigc))
221             bigc = rchild(n);
222         if(pri(bigc) <= pri(n))
223             break;
224         swap(n, bigc);
225         n = bigc;
226     }
227 }
228
229 void SGTimerQueue::siftUp(int n)
230 {
231     while((n != 0) && (_table[n].pri > _table[parent(n)].pri)) {
232         swap(n, parent(n));
233         n = parent(n);
234     }
235     siftDown(n);
236 }
237
238 void SGTimerQueue::growArray()
239 {
240     _tableSize = ((_tableSize+1)<<1) - 1;
241     HeapEntry *newTable = new HeapEntry[_tableSize];
242     for(int i=0; i<_numEntries; i++) {
243         newTable[i].pri  = _table[i].pri;
244         newTable[i].timer = _table[i].timer;
245     }
246     delete[] _table;
247     _table = newTable;
248 }
249
250 SGTimer* SGTimerQueue::findByName(const std::string& name) const
251 {
252   for (int i=0; i < _numEntries; ++i) {
253     if (_table[i].timer->name == name) {
254       return _table[i].timer;
255     }
256   }
257   
258   return NULL;
259 }