From 541c8c407b7ba8dd10f85bb48bcb5900270b3f84 Mon Sep 17 00:00:00 2001 From: Mathias Gumz Date: Tue, 28 Aug 2012 10:51:55 +0200 Subject: changed timing functions to use a monotonic increasing clock gettimeofday() is subject to be changed on daylight-saving or to ntp-related (think leap-seconds). even worse, it is subject to be changed BACK in time. this is hard to fix correctly (see commit 45726d3016e and bug #3560509). it is irrelevant for timers to know the nano-seconds since the epoch anyways. --- configure.in | 68 ++++++++---- src/AttentionNoticeHandler.cc | 2 +- src/ClockTool.cc | 37 ++----- src/FbTk/FbTime.cc | 97 ++++++++++++++++ src/FbTk/FbTime.hh | 58 ++++++++++ src/FbTk/ImageControl.cc | 2 +- src/FbTk/Makefile.am | 1 + src/FbTk/Menu.cc | 4 +- src/FbTk/Timer.cc | 232 +++++++++++++++------------------------ src/FbTk/Timer.hh | 61 +++------- src/Slit.cc | 2 +- src/Toolbar.cc | 2 +- src/TooltipWindow.cc | 17 +-- src/TooltipWindow.hh | 2 +- src/Window.cc | 34 ++---- src/Window.hh | 9 +- src/fluxbox.cc | 11 +- src/tests/testDemandAttention.cc | 5 +- src/tests/titletest.cc | 5 +- 19 files changed, 364 insertions(+), 285 deletions(-) create mode 100644 src/FbTk/FbTime.cc create mode 100644 src/FbTk/FbTime.hh diff --git a/configure.in b/configure.in index 14f1993..8ec02d5 100644 --- a/configure.in +++ b/configure.in @@ -35,7 +35,7 @@ AC_HEADER_STDC AC_HEADER_STDBOOL AC_CHECK_HEADERS(errno.h ctype.h dirent.h fcntl.h libgen.h \ locale.h math.h nl_types.h process.h signal.h stdarg.h \ - stdio.h time.h unistd.h \ + stdint.h stdio.h time.h unistd.h \ sys/param.h sys/select.h sys/signal.h sys/stat.h \ sys/time.h sys/types.h sys/wait.h \ langinfo.h iconv.h) @@ -48,7 +48,7 @@ AC_CHECK_HEADERS(sstream, , )] ) -AC_CHECK_HEADERS(cassert cctype cerrno cmath cstdarg cstdio cstdlib cstring ctime) +AC_CHECK_HEADERS(cassert cctype cerrno cmath cstdarg cstdint cstdio cstdlib cstring ctime) dnl Check for existance of basename(), setlocale() and strftime() @@ -61,10 +61,11 @@ AC_FUNC_SELECT_ARGTYPES AC_FUNC_STAT AC_CHECK_FUNCS(basename, , AC_CHECK_LIB(gen, basename, LIBS="-lgen $LIBS")) -AC_CHECK_FUNCS(catclose catgets catopen getpid gettimeofday memset mkdir \ +AC_CHECK_FUNCS(catclose catgets catopen getpid memset mkdir \ nl_langinfo putenv regcomp select setenv setlocale sigaction snprintf \ sqrt strcasecmp strcasestr strchr strstr strtol strtoul sync vsnprintf) + dnl Windows requires the mingw-catgets library for the catgets function. AC_SEARCH_LIBS([catgets], [catgets], [], []) @@ -92,6 +93,48 @@ size_t x = strftime(s, 5, "%a", localtime(&t)); [AC_MSG_RESULT(no)]) +AC_MSG_CHECKING(for clock_gettime) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [#include ], + [[ + clock_gettime(CLOCK_MONOTONIC, 0); + return 0; + ]] + )], + [ + AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define to 1 if you have the 'clock_gettime' function.]) + AC_MSG_RESULT(yes) + # *bsd has clock_gettime() in libc + AC_CHECK_LIB(rt, clock_gettime, LIBS="-lrt $LIBS") + ], + [ + AC_MSG_RESULT(no) + ] +) + +AC_MSG_CHECKING(for mach_absolute_time) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [#include ], + [[ + mach_absolute_time(); + return 0; + ]] + )], + [ + AC_DEFINE(HAVE_MACH_ABSOLUTE_TIME, 1, [Define to 1 if you have the 'mach_absolute_time' function.]) + AC_MSG_RESULT(yes) + #AC_CHECK_LIB(, clock_gettime, LIBS="-lrt $LIBS") + ], + [ + AC_MSG_RESULT(no) + ] +) + + + + AC_STRUCT_TM dnl --------------- @@ -130,18 +173,8 @@ if test "x$ac_cv_header_iconv_h" = "xyes"; then if test "x$ac_found_iconv" = xyes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) - AC_CHECK_LIB([iconv], - [iconv_open], - [ - LIBS="-liconv $LIBS" - ], - []) - AC_CHECK_LIB([iconv], - [libiconv_open], - [ - LIBS="-liconv $LIBS" - ], - []) + AC_CHECK_LIB(iconv, iconv_open, LIBS="-liconv $LIBS") + AC_CHECK_LIB(iconv, libiconv_open, LIBS="-liconv $LIBS") dnl Check if iconv uses const in prototype declaration AC_CACHE_CHECK(for iconv declaration, @@ -185,10 +218,7 @@ LDFLAGS="$LDFLAGS $LIBS $X_PRE_LIBS" dnl Check for required functions in -lX11 -AC_CHECK_LIB(X11, XOpenDisplay, - LIBS="-lX11 $LIBS", - AC_MSG_ERROR([Could not find XOpenDisplay in -lX11.]) -) +AC_CHECK_LIB(X11, XOpenDisplay, LIBS="-lX11 $LIBS", AC_MSG_ERROR([Could not find XOpenDisplay in -lX11.])) LIBS="$X_EXTRA_LIBS $LIBS" AC_CHECK_LIB(xpg4, setlocale, LIBS="-lxpg4 $LIBS") diff --git a/src/AttentionNoticeHandler.cc b/src/AttentionNoticeHandler.cc index 0aaf266..1bb28b2 100644 --- a/src/AttentionNoticeHandler.cc +++ b/src/AttentionNoticeHandler.cc @@ -81,7 +81,7 @@ void AttentionNoticeHandler::addAttention(Focusable &client) { RefCount > cmd(new ToggleFrameFocusCmd(client)); Timer *timer = new Timer(); timer->setCommand(cmd); - timer->setTimeout(**timeout_res); + timer->setTimeout(**timeout_res * FbTk::FbTime::IN_MILLISECONDS); timer->fireOnce(false); // will repeat until window has focus timer->start(); diff --git a/src/ClockTool.cc b/src/ClockTool.cc index 95176a2..1fcdb53 100644 --- a/src/ClockTool.cc +++ b/src/ClockTool.cc @@ -35,6 +35,7 @@ #include "FbTk/Menu.hh" #include "FbTk/MenuItem.hh" #include "FbTk/I18n.hh" +#include "FbTk/FbTime.hh" #ifdef HAVE_CONFIG_H #include "config.h" @@ -45,16 +46,15 @@ #else #include #endif -#include #include - +#include namespace { -static const char SWITCHES_SECONDS[] = "crsSTX+"; -static const char SWITCHES_12_24H[] = "lIrkHT"; -static const char SWITCHES_24_12H[] = "kHTlIr"; -static const char SWITCH_AM_PM[] = "pP"; +const char SWITCHES_SECONDS[] = "crsSTX+"; +const char SWITCHES_12_24H[] = "lIrkHT"; +const char SWITCHES_24_12H[] = "kHTlIr"; +const char SWITCH_AM_PM[] = "pP"; /** * return true if clock shows seconds. If clock doesn't show seconds then @@ -68,23 +68,13 @@ int showSeconds(const std::string& fmt_string) { } -timeval calcNextTimeout(const std::string& fmt_string) { - timeval now; - timeval next; - gettimeofday(&now, 0); - next.tv_sec = 60 - (now.tv_sec % 60) - 1; - next.tv_usec = 1000000 - now.tv_usec; - if (next.tv_usec >= 1000000) { - next.tv_sec++; - next.tv_usec -= 1000000; - } +uint64_t calcNextTimeout(const std::string& fmt_string) { - // wake up at next second-change - if (showSeconds(fmt_string)) { - next.tv_sec = 0; + if (showSeconds(fmt_string)) { // microseconds till next full second + return FbTk::FbTime::remainingNext(FbTk::FbTime::IN_SECONDS); + } else { // microseconds until next full minute + return FbTk::FbTime::remainingNext(60L * FbTk::FbTime::IN_SECONDS); } - - return next; } @@ -278,13 +268,10 @@ unsigned int ClockTool::height() const { } void ClockTool::updateTime() { - // update clock - timeval now; - gettimeofday(&now, 0); - time_t the_time = now.tv_sec; m_timer.setTimeout(calcNextTimeout(*m_timeformat)); + time_t the_time = time(NULL); if (the_time != -1) { char time_string[255]; int time_string_len; diff --git a/src/FbTk/FbTime.cc b/src/FbTk/FbTime.cc new file mode 100644 index 0000000..54eda75 --- /dev/null +++ b/src/FbTk/FbTime.cc @@ -0,0 +1,97 @@ +// FbTime.cc for FbTk - Fluxbox Toolkit +// Copyright (c) 2012 Mathias Gumz (akira at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#include "FbTime.hh" + + + +#ifdef HAVE_CLOCK_GETTIME // linux|*bsd|solaris +#include + +namespace { + +uint64_t _now() { + + uint64_t n = 0L; + timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + n = (ts.tv_sec * FbTk::FbTime::IN_SECONDS) + (ts.tv_nsec / 1000L); + } + + return n; +} + +} + +#endif // HAVE_CLOCK_GETTIME + + + + + +#ifdef HAVE_MACH_ABSOLUTE_TIME // macosx + +// http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x +// https://github.com/ThomasHabets/monotonic_clock/blob/master/src/monotonic_mach.c +// http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/ + + +#include + +namespace { + +uint64_t _now() { + + // mach_absolute_time() * info.numer / info.denom yields + // nanoseconds. + + static double micro_scale = 0.001; // 1000ms == 1ns + static bool initial = true; + + if (initial) { + initial = false; + mach_timebase_info_data_t info; + if (mach_timebase_info(&info) == 0) { + micro_scale *= static_castinfo.numer / static_cast(info.denom); + } + } + + return static_cast(mach_absolute_time() * micro_scale); +} + +} + +#endif // HAVE_MACH_ABSOLUTE_TIME + + + + + +uint64_t FbTk::FbTime::now() { + return ::_now(); +} + + +uint64_t FbTk::FbTime::remainingNext(uint64_t unit) { + return (unit - (::_now() % unit) - 1); +} + diff --git a/src/FbTk/FbTime.hh b/src/FbTk/FbTime.hh new file mode 100644 index 0000000..2b33dd8 --- /dev/null +++ b/src/FbTk/FbTime.hh @@ -0,0 +1,58 @@ +// FbTime.hh for FbTk - Fluxbox Toolkit +// Copyright (c) 2012 Mathias Gumz (akira at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef FBTK_FBTIME_HH +#define FBTK_FBTIME_HH + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + + +#ifdef HAVE_INTTYPES_H +#include +#endif // HAVE_INTTYPES_H + +namespace FbTk { + +// time in micro-seconds, monotonic increasing +// +// interesting links: +// +// http://www.python.org/dev/peps/pep-0418/#operating-system-time-functions +// http://en.cppreference.com/w/cpp/chrono + +namespace FbTime { + + const uint64_t IN_MILLISECONDS = 1000L; + const uint64_t IN_SECONDS = 1000L * 1000L; + + uint64_t now(); + + // calculates the remaining microseconds up to the next full 'unit' + uint64_t remainingNext(uint64_t unit); + +} // namespace FbTime + +} // namespace FbTk + +#endif // FBTK_TIME_HH diff --git a/src/FbTk/ImageControl.cc b/src/FbTk/ImageControl.cc index fe6fde0..c99ef9a 100644 --- a/src/FbTk/ImageControl.cc +++ b/src/FbTk/ImageControl.cc @@ -188,7 +188,7 @@ ImageControl::ImageControl(int screen_num, cache_max = cmax; if (cache_timeout && s_timed_cache) { - m_timer.setTimeout(cache_timeout); + m_timer.setTimeout(cache_timeout * FbTk::FbTime::IN_MILLISECONDS); RefCount > clean_cache(new SimpleCommand(*this, &ImageControl::cleanCache)); m_timer.setCommand(clean_cache); m_timer.start(); diff --git a/src/FbTk/Makefile.am b/src/FbTk/Makefile.am index 171f27d..298b8c5 100644 --- a/src/FbTk/Makefile.am +++ b/src/FbTk/Makefile.am @@ -36,6 +36,7 @@ libFbTk_a_SOURCES = App.hh App.cc Color.cc Color.hh Command.hh \ Texture.cc Texture.hh TextureRender.hh TextureRender.cc \ Shape.hh Shape.cc \ Theme.hh Theme.cc ThemeItems.cc Timer.hh Timer.cc \ + FbTime.cc FbTime.hh \ XFontImp.cc XFontImp.hh \ Button.hh Button.cc \ TextButton.hh TextButton.cc \ diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc index a66b6c0..3632fc9 100644 --- a/src/FbTk/Menu.cc +++ b/src/FbTk/Menu.cc @@ -1006,7 +1006,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { } if (itmp->submenu()) { // start submenu open delay - m_submenu_timer.setTimeout(theme()->getDelay()); + m_submenu_timer.setTimeout(theme()->getDelay() * FbTk::FbTime::IN_MILLISECONDS); m_submenu_timer.start(); } else if (isItemSelectable(w)){ // else normal menu item @@ -1225,7 +1225,7 @@ void Menu::closeMenu() { } void Menu::startHide() { - m_hide_timer.setTimeout(theme()->getDelay()); + m_hide_timer.setTimeout(theme()->getDelay() * FbTk::FbTime::IN_MILLISECONDS); m_hide_timer.start(); } diff --git a/src/FbTk/Timer.cc b/src/FbTk/Timer.cc index 8b144db..6a478bd 100644 --- a/src/FbTk/Timer.cc +++ b/src/FbTk/Timer.cc @@ -1,5 +1,5 @@ // Timer.cc for FbTk - Fluxbox Toolkit -// Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org) +// Copyright (c) 2003 - 2012 Henrik Kinnunen (fluxgen at fluxbox dot org) // // Timer.cc for Blackbox - An X11 Window Manager // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net) @@ -32,10 +32,6 @@ #define _GNU_SOURCE #endif // _GNU_SOURCE -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif // HAVE_CONFIG_H - #ifdef HAVE_CASSERT #include #else @@ -55,9 +51,48 @@ # include #endif -namespace FbTk { +#include +#include + + +namespace { + +struct TimerCompare { + bool operator() (const FbTk::Timer* a, const FbTk::Timer* b) { + return a->getEndTime() < b->getEndTime(); + } +}; +typedef std::set TimerList; + +TimerList s_timerlist; + + +/// add a timer to the static list +void addTimer(FbTk::Timer *timer) { + + assert(timer); + int interval = timer->getInterval(); + + // interval timers have their timeout change every time they are started! + if (interval != 0) { + timer->setTimeout(interval * FbTk::FbTime::IN_SECONDS); + } + + s_timerlist.insert(timer); +} -Timer::TimerList Timer::m_timerlist; +/// remove a timer from the static list +void removeTimer(FbTk::Timer *timer) { + + assert(timer); + s_timerlist.erase(timer); +} + + +} + + +namespace FbTk { Timer::Timer():m_timing(false), m_once(false), m_interval(0) { @@ -76,22 +111,8 @@ Timer::~Timer() { } -void Timer::setTimeout(time_t t) { - m_timeout.tv_sec = t / 1000; - m_timeout.tv_usec = t; - m_timeout.tv_usec -= (m_timeout.tv_sec * 1000); - m_timeout.tv_usec *= 1000; -} - - -void Timer::setTimeout(const timeval &t) { - m_timeout.tv_sec = t.tv_sec; - m_timeout.tv_usec = t.tv_usec; -} - -void Timer::setTimeout(unsigned int secs, unsigned int usecs) { - m_timeout.tv_sec = secs; - m_timeout.tv_usec = usecs; +void Timer::setTimeout(uint64_t timeout) { + m_timeout = timeout; } void Timer::setCommand(const RefCount > &cmd) { @@ -99,28 +120,24 @@ void Timer::setCommand(const RefCount > &cmd) { } void Timer::start() { - gettimeofday(&m_start, 0); + + m_start = FbTk::FbTime::now(); // only add Timers that actually DO something if ((! m_timing || m_interval != 0) && m_handler) { m_timing = true; - addTimer(this); //add us to the list + ::addTimer(this); } } void Timer::stop() { m_timing = false; - removeTimer(this); //remove us from the list + ::removeTimer(this); } -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++; - } +uint64_t Timer::getEndTime() const { + return m_start + m_timeout; } @@ -129,42 +146,34 @@ void Timer::fireTimeout() { (*m_handler)(); } + void Timer::updateTimers(int fd) { + fd_set rfds; - timeval now, tm, *timeout = 0; + timeval tm; + timeval* timeout = 0; + TimerList::iterator it; FD_ZERO(&rfds); FD_SET(fd, &rfds); bool overdue = false; + uint64_t now = FbTime::now(); + uint64_t end_time; // see, if the first timer in the // list is overdue - if (!m_timerlist.empty()) { - gettimeofday(&now, 0); - - Timer *timer = m_timerlist.front(); - - timer->makeEndTime(tm); + if (!s_timerlist.empty()) { - tm.tv_sec -= now.tv_sec; - tm.tv_usec -= now.tv_usec; + Timer* timer = *s_timerlist.begin(); + end_time = timer->getEndTime(); - 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) { // usec zero-ed above if negative - tm.tv_sec = 0; - tm.tv_usec = 0; + if (end_time < now) { overdue = true; + } else { + uint64_t diff = (end_time - now); + tm.tv_sec = diff / FbTime::IN_SECONDS; + tm.tv_usec = diff % FbTime::IN_SECONDS; } timeout = &tm; @@ -173,100 +182,41 @@ void Timer::updateTimers(int fd) { // if not overdue, wait for the next xevent via the blocking // select(), so OS sends fluxbox to sleep. the select() will // time out when the next timer has to be handled - if (!overdue && select(fd + 1, &rfds, 0, 0, timeout) != 0) + if (!overdue && select(fd + 1, &rfds, 0, 0, timeout) != 0) { // didn't time out! x events are pending return; - - TimerList::iterator it; - - // 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); + now = FbTime::now(); + for (it = s_timerlist.begin(); it != s_timerlist.end(); ) { - t.makeEndTime(tm); - - if (((now.tv_sec < tm.tv_sec) || - (now.tv_sec == tm.tv_sec && now.tv_usec < tm.tv_usec))) + // t->fireTimeout() might add timers to the list + // this invalidates 'it'. thus we store the current + // item here + Timer* t = *it; + if (now < t->getEndTime()) { break; - - t.fireTimeout(); - // restart the current timer so that the start time is updated - if (! t.doOnce()) { - // 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(); - } else { - // Since the default stop behaviour results in the timer - // being removed, we must remove it here, so that the iterator - // lives well. Another option would be to add it to another - // list, and then just go through that list and stop them all. - it = m_timerlist.erase(it); - t.stop(); } - } -} + t->fireTimeout(); -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) { - tm.tv_sec = timer->getStartTime().tv_sec; - tm.tv_usec = timer->getStartTime().tv_usec; - - // now convert to interval - tm.tv_sec = interval - (tm.tv_sec % interval) - 1; - tm.tv_usec = 1000000 - tm.tv_usec; - if (tm.tv_usec == 1000000) { - tm.tv_usec = 0; - tm.tv_sec += 1; - } - timer->setTimeout(tm); - } - - // set timeval to the time-of-trigger - timer->makeEndTime(tm); + // find the iterator to the timer again + // and continue working on the list + it = s_timerlist.find(t); + it++; + s_timerlist.erase(t); - // 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(); - 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; + if (! t->doOnce()) { // restart the current timer + t->m_timing = false; + t->start(); + } else { + t->stop(); } } - m_timerlist.insert(it, timer); } + Command *DelayedCmd::parse(const std::string &command, const std::string &args, bool trusted) { @@ -280,7 +230,7 @@ Command *DelayedCmd::parse(const std::string &command, if (cmd == 0) return 0; - int delay = 200000; + int delay = 200; StringUtil::fromString(args.c_str() + err, delay); return new DelayedCmd(cmd, delay); @@ -294,10 +244,7 @@ DelayedCmd::DelayedCmd(const RefCount > &cmd, unsigned int timeout) { } void DelayedCmd::initTimer(unsigned int timeout) { - timeval to; - to.tv_sec = timeout/1000000; - to.tv_usec = timeout % 1000000; - m_timer.setTimeout(to); + m_timer.setTimeout(timeout * FbTime::IN_MILLISECONDS); m_timer.fireOnce(true); } @@ -307,9 +254,4 @@ void DelayedCmd::execute() { m_timer.start(); } -void Timer::removeTimer(Timer *timer) { - assert(timer); - m_timerlist.remove(timer); -} - } // end namespace FbTk diff --git a/src/FbTk/Timer.hh b/src/FbTk/Timer.hh index 376eac0..241e327 100644 --- a/src/FbTk/Timer.hh +++ b/src/FbTk/Timer.hh @@ -27,26 +27,13 @@ #include "RefCount.hh" #include "Command.hh" - -#ifdef HAVE_CTIME - #include -#else - #include -#endif -#include -#include +#include "FbTime.hh" #ifdef HAVE_CONFIG_H #include "config.h" #endif //HAVE_CONFIG_H -#ifdef HAVE_INTTYPES_H -#include -#endif // HAVE_INTTYPES_H - -#include -#include -#include +#include namespace FbTk { @@ -57,24 +44,21 @@ class Timer { public: Timer(); explicit Timer(const RefCount > &handler); - virtual ~Timer(); + ~Timer(); void fireOnce(bool once) { m_once = once; } - /// set timeout - void setTimeout(time_t val); - /// set timeout - void setTimeout(const timeval &val); - void setTimeout(unsigned int secs, unsigned int usecs); + void setTimeout(uint64_t timeout); void setCommand(const RefCount > &cmd); + template - void setFunctor(const Functor &functor) - { setCommand(RefCount >(new SlotImpl(functor))); } - void setInterval(int val) { m_interval = val; } - /// start timing + void setFunctor(const Functor &functor) { + setCommand(RefCount >(new SlotImpl(functor))); + } + + void setInterval(int seconds) { m_interval = seconds; } void start(); - /// stop timing void stop(); - /// update all timers + static void updateTimers(int file_descriptor); int isTiming() const { return m_timing; } @@ -82,38 +66,29 @@ public: 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; + uint64_t getTimeout() const { return m_timeout; } + uint64_t getStartTime() const { return m_start; } + uint64_t getEndTime() const; protected: /// force a timeout void fireTimeout(); private: - /// add a timer to the static list - static void addTimer(Timer *timer); - /// remove a timer from the static list - static void removeTimer(Timer *timer); - - typedef std::list TimerList; - static TimerList m_timerlist; ///< list of all timers, sorted by next trigger time (start + timeout) - RefCount > m_handler; ///< what to do on a timeout bool m_timing; ///< clock running? bool m_once; ///< do timeout only once? - int m_interval; ///< Is an interval-only timer (e.g. clock) - // note that intervals only take note of the seconds, not microseconds + int m_interval; ///< Is an interval-only timer (e.g. clock), in seconds - timeval m_start; ///< start time - timeval m_timeout; ///< time length + uint64_t m_start; ///< start time in microseconds + uint64_t m_timeout; ///< time length in microseconds }; /// executes a command after a specified timeout class DelayedCmd: public Command { public: - DelayedCmd(const RefCount > &cmd, unsigned int timeout = 200000); + DelayedCmd(const RefCount > &cmd, unsigned int timeout = 200); // this constructor has inverted order of parameters to avoid ambiguity with the previous // constructor diff --git a/src/Slit.cc b/src/Slit.cc index 02eb877..738a81a 100644 --- a/src/Slit.cc +++ b/src/Slit.cc @@ -279,7 +279,7 @@ Slit::Slit(BScreen &scr, FbTk::Layer &layer, const char *filename) // move the frame out of sight for a moment frame.window.move(-frame.window.width(), -frame.window.height()); // setup timer - m_timer.setTimeout(200); // default timeout + m_timer.setTimeout(200L * FbTk::FbTime::IN_MILLISECONDS); // default timeout m_timer.fireOnce(true); FbTk::RefCount > toggle_hidden(new FbTk::SimpleCommand(*this, &Slit::toggleHidden)); m_timer.setCommand(toggle_hidden); diff --git a/src/Toolbar.cc b/src/Toolbar.cc index a8b2c5b..1c22440 100644 --- a/src/Toolbar.cc +++ b/src/Toolbar.cc @@ -258,7 +258,7 @@ Toolbar::Toolbar(BScreen &scrn, FbTk::Layer &layer, size_t width): frame.grab_x = frame.grab_y = 0; // setup hide timer - m_hide_timer.setTimeout(Fluxbox::instance()->getAutoRaiseDelay()); + m_hide_timer.setTimeout(Fluxbox::instance()->getAutoRaiseDelay() * FbTk::FbTime::IN_MILLISECONDS); FbTk::RefCount > toggle_hidden(new FbTk::SimpleCommand(*this, &Toolbar::toggleHidden)); m_hide_timer.setCommand(toggle_hidden); m_hide_timer.fireOnce(true); diff --git a/src/TooltipWindow.cc b/src/TooltipWindow.cc index 0fb7273..77a6e1e 100644 --- a/src/TooltipWindow.cc +++ b/src/TooltipWindow.cc @@ -55,8 +55,11 @@ void TooltipWindow::raiseTooltip() { resize(m_lastText); reconfigTheme(); - int h = theme()->iconbarTheme().text().font().height() + theme()->bevelWidth() * 2; - int w = theme()->iconbarTheme().text().font().textWidth(m_lastText) + theme()->bevelWidth() * 2; + + FbTk::Font& font = theme()->iconbarTheme().text().font(); + + int h = font.height() + theme()->bevelWidth() * 2; + int w = font.textWidth(m_lastText) + theme()->bevelWidth() * 2; Window root_ret; // not used Window window_ret; // not used @@ -91,11 +94,11 @@ void TooltipWindow::raiseTooltip() { show(); clear(); // TODO: make this use a TextButton like TextDialog does - theme()->iconbarTheme().text().font().drawText(*this, screen().screenNumber(), - theme()->iconbarTheme().text().textGC(), - m_lastText, - theme()->bevelWidth(), - theme()->bevelWidth() + theme()->iconbarTheme().text().font().ascent()); + font.drawText(*this, screen().screenNumber(), + theme()->iconbarTheme().text().textGC(), + m_lastText, + theme()->bevelWidth(), + theme()->bevelWidth() + font.ascent()); } void TooltipWindow::updateText(const FbTk::BiDiString& text) { diff --git a/src/TooltipWindow.hh b/src/TooltipWindow.hh index 4d028b5..67bec90 100644 --- a/src/TooltipWindow.hh +++ b/src/TooltipWindow.hh @@ -47,7 +47,7 @@ public: /// Sets the delay before the window pops up void setDelay(int delay) { m_delay = delay; - m_timer.setTimeout(delay); + m_timer.setTimeout(delay * FbTk::FbTime::IN_MILLISECONDS); } void hide(); diff --git a/src/Window.cc b/src/Window.cc index 597bc08..33a4c9e 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -416,7 +416,7 @@ void FluxboxWindow::init() { updateMWMHintsFromClient(*m_client); - m_timer.setTimeout(fluxbox.getAutoRaiseDelay()); + m_timer.setTimeout(fluxbox.getAutoRaiseDelay() * FbTk::FbTime::IN_MILLISECONDS); FbTk::RefCount > raise_cmd(new FbTk::SimpleCommand(*this, &FluxboxWindow::raise)); m_timer.setCommand(raise_cmd); @@ -538,9 +538,7 @@ void FluxboxWindow::init() { m_workspacesig.emit(*this); - struct timeval now; - gettimeofday(&now, NULL); - m_creation_time = now.tv_sec; + m_creation_time = FbTk::FbTime::now(); frame().frameExtentSig().emit(); @@ -1049,15 +1047,10 @@ void FluxboxWindow::grabButtons() { void FluxboxWindow::reconfigure() { applyDecorations(); - setFocusFlag(m_focused); - moveResize(frame().x(), frame().y(), frame().width(), frame().height()); - - m_timer.setTimeout(Fluxbox::instance()->getAutoRaiseDelay()); - + m_timer.setTimeout(Fluxbox::instance()->getAutoRaiseDelay() * FbTk::FbTime::IN_MILLISECONDS); updateButtons(); - frame().reconfigure(); menu().reconfigure(); @@ -2200,14 +2193,14 @@ void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) { // don't let misbehaving clients (e.g. MPlayer) move/resize their windows // just after creation if the user has a saved position/size if (m_creation_time) { - struct timeval now; - gettimeofday(&now, NULL); + + uint64_t now = FbTk::FbTime::now(); Remember& rinst = Remember::instance(); - if (now.tv_sec > m_creation_time + 1) + if (now > (m_creation_time + FbTk::FbTime::IN_SECONDS)) { m_creation_time = 0; - else if (rinst.isRemembered(*client, Remember::REM_MAXIMIZEDSTATE) || + } else if (rinst.isRemembered(*client, Remember::REM_MAXIMIZEDSTATE) || rinst.isRemembered(*client, Remember::REM_FULLSCREENSTATE)) { cr.value_mask = cr.value_mask & ~(CWWidth | CWHeight); cr.value_mask = cr.value_mask & ~(CWX | CWY); @@ -2300,23 +2293,18 @@ void FluxboxWindow::keyPressEvent(XKeyEvent &ke) { // e.g., typed the command in a terminal if (ks == XK_KP_Enter || ks == XK_Return) { // we'll actually reset the time for this one - m_last_keypress_time.tv_sec = 0; + m_last_keypress_time = 0; return; } // otherwise, make a note that the user is typing - gettimeofday(&m_last_keypress_time, 0); + m_last_keypress_time = FbTk::FbTime::now(); } bool FluxboxWindow::isTyping() const { - timeval now; - if (gettimeofday(&now, NULL) == -1) - return false; - - unsigned int diff = 1000*(now.tv_sec - m_last_keypress_time.tv_sec); - diff += (now.tv_usec - m_last_keypress_time.tv_usec)/1000; - return (diff < screen().noFocusWhileTypingDelay()); + uint64_t diff = FbTk::FbTime::now() - m_last_keypress_time; + return ((diff / 1000) < screen().noFocusWhileTypingDelay()); } void FluxboxWindow::buttonPressEvent(XButtonEvent &be) { diff --git a/src/Window.hh b/src/Window.hh index 8c97c7b..09374af 100644 --- a/src/Window.hh +++ b/src/Window.hh @@ -33,11 +33,11 @@ #include "FbTk/DefaultValue.hh" #include "FbTk/Timer.hh" +#include "FbTk/FbTime.hh" #include "FbTk/EventHandler.hh" #include "FbTk/LayerItem.hh" #include "FbTk/Signal.hh" -#include #include #include #include @@ -529,14 +529,15 @@ private: // state and hint signals FbTk::Signal m_workspacesig, m_statesig, m_layersig, m_hintsig; - time_t m_creation_time; + uint64_t m_creation_time; + uint64_t m_last_keypress_time; + FbTk::Timer m_timer; // Window states bool moving, resizing, m_initialized; WinClient *m_attaching_tab; - FbTk::Timer m_timer; Display *display; /// display connection int m_button_grab_x, m_button_grab_y; // handles last button press event for move @@ -545,8 +546,6 @@ private: int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window" int m_last_pressed_button; - timeval m_last_keypress_time; - unsigned int m_workspace_number; unsigned long m_current_state; // NormalState | IconicState | Withdrawn diff --git a/src/fluxbox.cc b/src/fluxbox.cc index 77b9881..129ac80 100644 --- a/src/fluxbox.cc +++ b/src/fluxbox.cc @@ -306,7 +306,7 @@ Fluxbox::Fluxbox(int argc, char **argv, // because it could affect ongoing menu stuff so we need to reconfig in // the next event "round". FbTk::RefCount > reconfig_cmd(new FbTk::SimpleCommand(*this, &Fluxbox::timed_reconfigure)); - m_reconfig_timer.setTimeout(0, 1); + m_reconfig_timer.setTimeout(1); m_reconfig_timer.setCommand(reconfig_cmd); m_reconfig_timer.fireOnce(true); @@ -363,7 +363,6 @@ Fluxbox::Fluxbox(int argc, char **argv, screens.push_back(i); // find out, on what "screens" fluxbox should run - // FIXME(php-coder): maybe it worths moving this code to main.cc, where command line is parsed? for (i = 1; i < m_argc; i++) { if (! strcmp(m_argv[i], "-screen")) { if ((++i) >= m_argc) { @@ -507,8 +506,11 @@ void Fluxbox::initScreen(BScreen *screen) { void Fluxbox::eventLoop() { + Display *disp = display(); + while (!m_shutdown) { + if (XPending(disp)) { XEvent e; XNextEvent(disp, &e); @@ -524,8 +526,9 @@ void Fluxbox::eventLoop() { handleEvent(&e); } } else { - FbTk::Timer::updateTimers(ConnectionNumber(disp)); //handle all timers + FbTk::Timer::updateTimers(ConnectionNumber(disp)); } + } } @@ -553,9 +556,11 @@ void Fluxbox::ungrab() { } void Fluxbox::handleEvent(XEvent * const e) { + _FB_USES_NLS; m_last_event = *e; + // it is possible (e.g. during moving) for a window // to mask all events to go to it if ((m_masked == e->xany.window) && m_masked_window) { diff --git a/src/tests/testDemandAttention.cc b/src/tests/testDemandAttention.cc index 10fadb3..914f369 100644 --- a/src/tests/testDemandAttention.cc +++ b/src/tests/testDemandAttention.cc @@ -61,10 +61,7 @@ public: FbTk::RefCount > cmd(new FbTk::SimpleCommand (*this, &App::demandAttention)); - timeval t; - t.tv_sec = 5; - t.tv_usec = 0; - m_timer.setTimeout(t); + m_timer.setTimeout(5 * FbTk::FbTime::IN_SECONDS); m_timer.setCommand(cmd); m_timer.fireOnce(false); m_timer.start(); diff --git a/src/tests/titletest.cc b/src/tests/titletest.cc index 9ea94f1..e16435a 100644 --- a/src/tests/titletest.cc +++ b/src/tests/titletest.cc @@ -52,10 +52,7 @@ public: FbTk::RefCount cmd(new FbTk::SimpleCommand (*this, &App::updateTitle)); - timeval t; - t.tv_sec = 0; - t.tv_usec = 150000; - m_timer.setTimeout(t); + m_timer.setTimeout(150 * FbTk::FbTime::IN_MILLISECONDS); m_timer.setCommand(cmd); m_timer.fireOnce(false); m_timer.start(); -- cgit v0.11.2