aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Gumz <akira at fluxbox dot org>2013-01-15 20:40:33 (GMT)
committerMathias Gumz <akira at fluxbox dot org>2013-01-15 20:40:33 (GMT)
commit33161595f482d0dad950ce127b6016eefe8ea691 (patch)
tree27fa5588b2ddd7410eb083d7bf0c8811d72f8270
parent239e895826b2f843bc50cc6fef8108db174c33e8 (diff)
downloadfluxbox_pavel-33161595f482d0dad950ce127b6016eefe8ea691.zip
fluxbox_pavel-33161595f482d0dad950ce127b6016eefe8ea691.tar.bz2
Simplifies and fix bugs in FbTk::Timer
* Calling Timer::setTimeout() from within Timer::start() might lead to ugly behavior (as experienced in bugs #3590078, #3600143, etc; see commit 4d307dcd10af9d817ff5c05fc40ae7487564cb31, fixes the problem partially). * Stop a timer first, then call the handler (via Timer::fireTimeout()). A given handler might call Timer::start() again, which (re)adds the Timer to the control list .. the following Timer::stop() would remove it again. * Use 'm_start' as indicator if timer is running. * Move the (now quite short) code of ::addTimer / ::removeTimer into the Timer::start() and Timer::stop() functions.
-rw-r--r--src/FbTk/Timer.cc72
-rw-r--r--src/FbTk/Timer.hh5
2 files changed, 36 insertions, 41 deletions
diff --git a/src/FbTk/Timer.cc b/src/FbTk/Timer.cc
index eff3af4..2404773 100644
--- a/src/FbTk/Timer.cc
+++ b/src/FbTk/Timer.cc
@@ -55,7 +55,6 @@
55#include <vector> 55#include <vector>
56#include <set> 56#include <set>
57 57
58
59namespace { 58namespace {
60 59
61struct TimerCompare { 60struct TimerCompare {
@@ -64,51 +63,30 @@ struct TimerCompare {
64 } 63 }
65}; 64};
66typedef std::set<FbTk::Timer*, TimerCompare> TimerList; 65typedef std::set<FbTk::Timer*, TimerCompare> TimerList;
67
68TimerList s_timerlist; 66TimerList s_timerlist;
69 67
70
71/// add a timer to the static list
72void addTimer(FbTk::Timer *timer) {
73
74 assert(timer);
75 int interval = timer->getInterval();
76
77 // interval timers have their timeout change every time they are started!
78 if (interval != 0) {
79 timer->setTimeout(interval * FbTk::FbTime::IN_SECONDS);
80 }
81
82 s_timerlist.insert(timer);
83}
84
85/// remove a timer from the static list
86void removeTimer(FbTk::Timer *timer) {
87
88 assert(timer);
89 s_timerlist.erase(timer);
90}
91
92
93} 68}
94 69
95 70
96namespace FbTk { 71namespace FbTk {
97 72
98Timer::Timer():m_timing(false), m_once(false), m_interval(0) { 73Timer::Timer() :
74 m_once(false),
75 m_interval(0),
76 m_start(0) {
99 77
100} 78}
101 79
102Timer::Timer(const RefCount<Slot<void> > &handler): 80Timer::Timer(const RefCount<Slot<void> > &handler):
103 m_handler(handler), 81 m_handler(handler),
104 m_timing(false),
105 m_once(false), 82 m_once(false),
106 m_interval(0) { 83 m_interval(0),
84 m_start(0) {
107} 85}
108 86
109 87
110Timer::~Timer() { 88Timer::~Timer() {
111 if (isTiming()) stop(); 89 stop();
112} 90}
113 91
114 92
@@ -131,19 +109,31 @@ void Timer::setCommand(const RefCount<Slot<void> > &cmd) {
131 109
132void Timer::start() { 110void Timer::start() {
133 111
134 m_start = FbTk::FbTime::now();
135
136 // only add Timers that actually DO something 112 // only add Timers that actually DO something
137 if ((! m_timing || m_interval != 0) && m_handler) { 113 if ( ( ! isTiming() || m_interval > 0 ) && m_handler) {
138 m_timing = true; 114
139 ::addTimer(this); 115 // in case start() gets triggered on a started
116 // timer with 'm_interval != 0' we have to remove
117 // it from s_timerlist before restarting it
118 stop();
119
120 m_start = FbTk::FbTime::now();
121
122 // interval timers have their timeout change every
123 // time they are started!
124 if (m_interval != 0) {
125 m_timeout = m_interval * FbTk::FbTime::IN_SECONDS;
126 }
127 s_timerlist.insert(this);
140 } 128 }
141} 129}
142 130
143 131
144void Timer::stop() { 132void Timer::stop() {
145 m_timing = false; 133 if (isTiming()) {
146 ::removeTimer(this); 134 s_timerlist.erase(this);
135 m_start = 0;
136 }
147} 137}
148 138
149uint64_t Timer::getEndTime() const { 139uint64_t Timer::getEndTime() const {
@@ -216,10 +206,16 @@ void Timer::updateTimers(int fd) {
216 206
217 FbTk::Timer& t = *timeouts[i]; 207 FbTk::Timer& t = *timeouts[i];
218 208
219 t.fireTimeout(); 209 // first we stop the timer to remove it
210 // from s_timerlist
220 t.stop(); 211 t.stop();
221 212
222 if (! t.doOnce()) { // restart the current timer 213 // then we call the handler which might (re)start 't'
214 // on it's own
215 t.fireTimeout();
216
217 // restart 't' if needed
218 if (!t.doOnce() && !t.isTiming()) {
223 t.start(); 219 t.start();
224 } 220 }
225 } 221 }
diff --git a/src/FbTk/Timer.hh b/src/FbTk/Timer.hh
index bdaf3b8..2e82f2a 100644
--- a/src/FbTk/Timer.hh
+++ b/src/FbTk/Timer.hh
@@ -61,7 +61,7 @@ public:
61 61
62 static void updateTimers(int file_descriptor); 62 static void updateTimers(int file_descriptor);
63 63
64 int isTiming() const { return m_timing; } 64 int isTiming() const { return (m_start > 0); }
65 int getInterval() const { return m_interval; } 65 int getInterval() const { return m_interval; }
66 66
67 int doOnce() const { return m_once; } 67 int doOnce() const { return m_once; }
@@ -77,11 +77,10 @@ protected:
77private: 77private:
78 RefCount<Slot<void> > m_handler; ///< what to do on a timeout 78 RefCount<Slot<void> > m_handler; ///< what to do on a timeout
79 79
80 bool m_timing; ///< clock running?
81 bool m_once; ///< do timeout only once? 80 bool m_once; ///< do timeout only once?
82 int m_interval; ///< Is an interval-only timer (e.g. clock), in seconds 81 int m_interval; ///< Is an interval-only timer (e.g. clock), in seconds
83 82
84 uint64_t m_start; ///< start time in microseconds 83 uint64_t m_start; ///< start time in microseconds, 0 if not running
85 uint64_t m_timeout; ///< time length in microseconds 84 uint64_t m_timeout; ///< time length in microseconds
86}; 85};
87 86