fix timer issues (esp clock not updating on multiple screens)

This commit is contained in:
simonb 2006-06-19 05:04:42 +00:00
parent 3bce4aab73
commit f6140840f8
4 changed files with 64 additions and 55 deletions

View file

@ -1,5 +1,10 @@
(Format: Year/Month/Day)
Changes for 1.0rc2:
*06/06/19:
* Fix bug #1507671, clock not updating on multiple screens (Simon)
- time() and gettimeofday() are inconsistent, only use gettimeofday
- clean up Timer stuff a bit, fixed some other bugs
FbTk/Timer.hh/cc ClockTool.cc
*06/06/18:
* Fixed bug #1507754 iconbar text was not updated to match titlebar (Henrik)
WinClient.cc

View file

@ -45,6 +45,7 @@
#else
#include <time.h>
#endif
#include <sys/time.h>
#include <string>
#include <typeinfo>
@ -242,7 +243,9 @@ unsigned int ClockTool::height() const {
void ClockTool::updateTime() {
// update clock
time_t the_time = time(0);
timeval now;
gettimeofday(&now, 0);
time_t the_time = now.tv_sec;
if (the_time != -1) {
char time_string[255];

View file

@ -98,6 +98,15 @@ void Timer::stop() {
removeTimer(this); //remove us from the list
}
void Timer::makeEndTime(timeval &tm) const {
tm.tv_sec = m_start.tv_sec + m_timeout.tv_sec;
tm.tv_usec = m_start.tv_usec + m_timeout.tv_usec;
if (tm.tv_usec >= 1000000) {
tm.tv_usec -= 1000000;
tm.tv_sec++;
}
}
void Timer::fireTimeout() {
if (*m_handler)
@ -111,79 +120,69 @@ void Timer::updateTimers(int fd) {
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
bool overdue = false;
if (!m_timerlist.empty()) {
gettimeofday(&now, 0);
tm.tv_sec = tm.tv_usec = 0l;
Timer *timer = m_timerlist.front();
const timeval &start = timer->getStartTime();
const timeval &length = timer->getTimeout();
tm.tv_sec = start.tv_sec +
length.tv_sec - now.tv_sec;
tm.tv_usec = start.tv_usec +
length.tv_usec - now.tv_usec;
timer->makeEndTime(tm);
while (tm.tv_usec >= 1000000) {
tm.tv_sec++;
tm.tv_usec -= 1000000;
}
tm.tv_sec -= now.tv_sec;
tm.tv_usec -= now.tv_usec;
while (tm.tv_usec < 0) {
if (tm.tv_sec > 0) {
tm.tv_sec--;
tm.tv_usec += 1000000;
} else {
overdue = true;
tm.tv_usec = 0;
break;
}
}
if (tm.tv_sec < 0) {
if (tm.tv_sec < 0) { // usec zero-ed above if negative
tm.tv_sec = 0;
tm.tv_usec = 0;
overdue = true;
}
timeout = &tm;
}
if (select(fd + 1, &rfds, 0, 0, timeout) != 0)
if (!overdue && select(fd + 1, &rfds, 0, 0, timeout) != 0)
// didn't time out! x events pending
return;
TimerList::iterator it;
// someone set the date of the machine BACK
// so we have to adjust the start_time
static time_t last_time = time(0);
if (time(0) < last_time) {
time_t delta = time(0) - last_time;
for (it = m_timerlist.begin(); it != m_timerlist.end(); it++) {
(*it)->m_start.tv_sec += delta;
}
}
// check for timer timeout
gettimeofday(&now, 0);
// someone set the date of the machine BACK
// so we have to adjust the start_time
static time_t last_time = 0;
if (now.tv_sec < last_time) {
time_t delta = last_time - now.tv_sec;
for (it = m_timerlist.begin(); it != m_timerlist.end(); it++) {
(*it)->m_start.tv_sec -= delta;
}
}
last_time = now.tv_sec;
//must check end ...the timer might remove
//it self from the list (should be fixed in the future)
for(it = m_timerlist.begin(); it != m_timerlist.end(); ) {
//This is to make sure we don't get an invalid iterator
//when we do fireTimeout
Timer &t = *(*it);
const timeval &start = t.getStartTime();
const timeval &length = t.getTimeout();
tm.tv_sec = start.tv_sec +
length.tv_sec;
tm.tv_usec = start.tv_usec +
length.tv_usec;
t.makeEndTime(tm);
if (((now.tv_sec < tm.tv_sec) ||
(now.tv_sec == tm.tv_sec && now.tv_usec < tm.tv_usec)))
@ -192,15 +191,10 @@ void Timer::updateTimers(int fd) {
t.fireTimeout();
// restart the current timer so that the start time is updated
if (! t.doOnce()) {
if (t.getInterval() != 0) {
it = m_timerlist.erase(it);
}
// must erase so that it's put into the right place in the list
it = m_timerlist.erase(it);
t.m_timing = false;
t.start();
// Note that this mustn't be done if we're deleting the
// entry from the list, so therefore it's not in the update
// section of the for loop
it++;
} else {
// Since the default stop behaviour results in the timer
// being removed, we must remove it here, so that the iterator
@ -211,15 +205,14 @@ void Timer::updateTimers(int fd) {
}
}
last_time = time(0);
}
void Timer::addTimer(Timer *timer) {
assert(timer);
int interval = timer->getInterval();
// interval timers have their timeout change every time they are started!
timeval tm;
if (interval != 0) {
timeval tm;
tm.tv_sec = timer->getStartTime().tv_sec;
tm.tv_usec = timer->getStartTime().tv_usec;
@ -233,13 +226,19 @@ void Timer::addTimer(Timer *timer) {
timer->setTimeout(tm);
}
// set timeval to the time-of-trigger
timer->makeEndTime(tm);
// timer list is sorted by trigger time (i.e. start plus timeout)
TimerList::iterator it = m_timerlist.begin();
TimerList::iterator it_end = m_timerlist.end();
int index = 0;
for (; it != it_end; ++it, ++index) {
if (((*it)->getTimeout().tv_sec > timer->getTimeout().tv_sec) ||
(((*it)->getTimeout().tv_sec == timer->getTimeout().tv_sec) &&
((*it)->getTimeout().tv_usec >= timer->getTimeout().tv_usec))) {
for (; it != it_end; ++it) {
timeval trig;
(*it)->makeEndTime(trig);
if ((trig.tv_sec > tm.tv_sec) ||
(trig.tv_sec == tm.tv_sec &&
trig.tv_usec >= tm.tv_usec)) {
break;
}
}

View file

@ -74,12 +74,14 @@ public:
/// update all timers
static void updateTimers(int file_descriptor);
inline int isTiming() const { return m_timing; }
inline int getInterval() const { return m_interval; }
inline int doOnce() const { return m_once; }
int isTiming() const { return m_timing; }
int getInterval() const { return m_interval; }
inline const timeval &getTimeout() const { return m_timeout; }
inline const timeval &getStartTime() const { return m_start; }
int doOnce() const { return m_once; }
const timeval &getTimeout() const { return m_timeout; }
const timeval &getStartTime() const { return m_start; }
void makeEndTime(timeval &tm) const;
protected:
/// force a timeout
@ -92,7 +94,7 @@ private:
static void removeTimer(Timer *timer);
typedef std::list<Timer *> TimerList;
static TimerList m_timerlist; ///< list of all timers
static TimerList m_timerlist; ///< list of all timers, sorted by next trigger time (start + timeout)
RefCount<Command> m_handler; ///< what to do on a timeout