diff options
| author | Dana Jansens <danakj@orodu.net> | 2002-11-03 14:29:34 +0000 |
|---|---|---|
| committer | Dana Jansens <danakj@orodu.net> | 2002-11-03 14:29:34 +0000 |
| commit | 9259ec5732851dd66f7c598d629e3808ac7ab3d8 (patch) | |
| tree | 5452b84b8937cde5f6977f26c24361cc1c0a5f08 /otk | |
| parent | ad80ef0f667e3b72d9e35d7a93451a1e2dfa0ab6 (diff) | |
new timer infrastructure. takes a function pointer for the timeout, with a void* parameter (useful for holding a class instance!)
Diffstat (limited to 'otk')
| -rw-r--r-- | otk/Makefile.am | 19 | ||||
| -rw-r--r-- | otk/image.hh | 11 | ||||
| -rw-r--r-- | otk/imagecontrol.cc | 20 | ||||
| -rw-r--r-- | otk/timer.cc | 186 | ||||
| -rw-r--r-- | otk/timer.hh | 124 |
5 files changed, 331 insertions, 29 deletions
diff --git a/otk/Makefile.am b/otk/Makefile.am index 7f862287..ada95b7f 100644 --- a/otk/Makefile.am +++ b/otk/Makefile.am @@ -5,7 +5,7 @@ INCLUDES= -I../src noinst_LIBRARIES=libotk.a libotk_a_SOURCES= color.cc display.cc font.cc gccache.cc image.cc \ - imagecontrol.cc rect.cc screeninfo.cc texture.cc + imagecontrol.cc rect.cc screeninfo.cc texture.cc timer.cc MAINTAINERCLEANFILES= Makefile.in @@ -13,16 +13,7 @@ distclean-local: rm -f *\~ *.orig *.rej .\#* # local dependencies -color.o: color.cc color.hh ../src/basedisplay.hh ../src/timer.hh ../src/util.hh -font.o: font.cc font.hh ../src/screen.hh color.hh texture.hh ../src/util.hh image.hh \ - ../src/timer.hh ../src/basedisplay.hh ../src/workspace.hh ../src/xatom.hh ../src/blackbox.hh \ - ../src/configuration.hh gccache.hh -gccache.o: gccache.cc gccache.hh ../src/basedisplay.hh ../src/timer.hh ../src/util.hh \ - color.hh -image.o: image.cc ../src/blackbox.hh ../src/basedisplay.hh ../src/timer.hh ../src/util.hh \ - ../src/configuration.hh ../src/xatom.hh gccache.hh color.hh image.hh texture.hh -imagecontrol.o: imagecontrol.cc ../src/blackbox.hh ../src/basedisplay.hh ../src/timer.hh \ - ../src/util.hh ../src/configuration.hh ../src/xatom.hh color.hh image.hh texture.hh -texture.o: texture.cc texture.hh color.hh ../src/util.hh ../src/basedisplay.hh \ - ../src/timer.hh image.hh ../src/screen.hh ../src/workspace.hh ../src/xatom.hh \ - ../src/blackbox.hh ../src/configuration.hh +color.o: color.cc color.hh display.hh screeninfo.hh rect.hh +gccache.o: gccache.cc gccache.hh display.hh color.hh assassin.hh \ + screeninfo.hh rect.hh +rect.o: rect.cc rect.hh diff --git a/otk/image.hh b/otk/image.hh index ac5794b5..ed99e124 100644 --- a/otk/image.hh +++ b/otk/image.hh @@ -11,7 +11,7 @@ extern "C" { #include "color.hh" #include "screeninfo.hh" -#include "src/timer.hh" +#include "timer.hh" namespace otk { @@ -66,7 +66,7 @@ public: }; -class BImageControl : public ob::TimeoutHandler { +class BImageControl { public: struct CachedImage { Pixmap pixmap; @@ -75,7 +75,8 @@ public: unsigned long pixel1, pixel2, texture; }; - BImageControl(const ScreenInfo *scrn, + BImageControl(OBTimerQueueManager *timermanager, + const ScreenInfo *scrn, bool _dither= False, int _cpc = 4, unsigned long cache_timeout = 300000l, unsigned long cmax = 200l); @@ -111,12 +112,12 @@ public: void setDither(bool d) { dither = d; } void setColorsPerChannel(int cpc); - virtual void timeout(void); + static void timeout(BImageControl *t); private: bool dither; const ScreenInfo *screeninfo; - ob::OBTimer *timer; + OBTimer *timer; Colormap colormap; diff --git a/otk/imagecontrol.cc b/otk/imagecontrol.cc index 7120f1cf..8cc6b2af 100644 --- a/otk/imagecontrol.cc +++ b/otk/imagecontrol.cc @@ -41,7 +41,8 @@ static unsigned long bsqrt(unsigned long x) { BImageControl *ctrl = 0; -BImageControl::BImageControl(const ScreenInfo *scrn, +BImageControl::BImageControl(OBTimerQueueManager *timermanager, + const ScreenInfo *scrn, bool _dither, int _cpc, unsigned long cache_timeout, unsigned long cmax) { @@ -53,12 +54,11 @@ BImageControl::BImageControl(const ScreenInfo *scrn, cache_max = cmax; if (cache_timeout) { - // XXX: FIX THIS - timer = 0;/*new BTimer(this); + timer = new OBTimer(timermanager, (OBTimeoutHandler)timeout, this); timer->setTimeout(cache_timeout); - timer->start();*/ + timer->start(); } else { - timer = (ob::OBTimer *) 0; + timer = (OBTimer *) 0; } colors = (XColor *) 0; @@ -420,7 +420,7 @@ Pixmap BImageControl::renderImage(unsigned int width, unsigned int height, "forcing cleanout\n"); #endif // DEBUG - timeout(); + timeout(this); } return pixmap; @@ -440,7 +440,7 @@ void BImageControl::removeImage(Pixmap pixmap) { } if (! timer) - timeout(); + timeout(this); } @@ -553,10 +553,10 @@ struct CacheCleaner { }; -void BImageControl::timeout(void) { +void BImageControl::timeout(BImageControl *t) { CacheCleaner cleaner; - std::for_each(cache.begin(), cache.end(), cleaner); - cache.remove_if(cleaner.ref_check); + std::for_each(t->cache.begin(), t->cache.end(), cleaner); + t->cache.remove_if(cleaner.ref_check); } } diff --git a/otk/timer.cc b/otk/timer.cc new file mode 100644 index 00000000..b2b85a66 --- /dev/null +++ b/otk/timer.cc @@ -0,0 +1,186 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "timer.hh" +#include "display.hh" +#include "util.hh" + +namespace otk { + +static timeval normalizeTimeval(const timeval &tm) +{ + timeval ret = tm; + + while (ret.tv_usec < 0) { + if (ret.tv_sec > 0) { + --ret.tv_sec; + ret.tv_usec += 1000000; + } else { + ret.tv_usec = 0; + } + } + + if (ret.tv_usec >= 1000000) { + ret.tv_sec += ret.tv_usec / 1000000; + ret.tv_usec %= 1000000; + } + + if (ret.tv_sec < 0) ret.tv_sec = 0; + + return ret; +} + + +OBTimer::OBTimer(OBTimerQueueManager *m, OBTimeoutHandler h, OBTimeoutData d) +{ + manager = m; + handler = h; + data = d; + + recur = timing = False; +} + + +OBTimer::~OBTimer(void) +{ + if (timing) stop(); +} + + +void OBTimer::setTimeout(long t) +{ + _timeout.tv_sec = t / 1000; + _timeout.tv_usec = t % 1000; + _timeout.tv_usec *= 1000; +} + + +void OBTimer::setTimeout(const timeval &t) +{ + _timeout.tv_sec = t.tv_sec; + _timeout.tv_usec = t.tv_usec; +} + + +void OBTimer::start(void) +{ + gettimeofday(&_start, 0); + + if (! timing) { + timing = True; + manager->addTimer(this); + } +} + + +void OBTimer::stop(void) +{ + timing = False; + + manager->removeTimer(this); +} + + +void OBTimer::halt(void) +{ + timing = False; +} + + +void OBTimer::fireTimeout(void) +{ + if (handler) + handler(data); +} + + +timeval OBTimer::timeRemaining(const timeval &tm) const +{ + timeval ret = endpoint(); + + ret.tv_sec -= tm.tv_sec; + ret.tv_usec -= tm.tv_usec; + + return normalizeTimeval(ret); +} + + +timeval OBTimer::endpoint(void) const +{ + timeval ret; + + ret.tv_sec = _start.tv_sec + _timeout.tv_sec; + ret.tv_usec = _start.tv_usec + _timeout.tv_usec; + + return normalizeTimeval(ret); +} + + +bool OBTimer::shouldFire(const timeval &tm) const +{ + timeval end = endpoint(); + + return ! ((tm.tv_sec < end.tv_sec) || + (tm.tv_sec == end.tv_sec && tm.tv_usec < end.tv_usec)); +} + + +void OBTimerQueueManager::fire() +{ + fd_set rfds; + timeval now, tm, *timeout = (timeval *) 0; + + const int xfd = ConnectionNumber(otk::OBDisplay::display); + + FD_ZERO(&rfds); + FD_SET(xfd, &rfds); // break on any x events + + if (! timerList.empty()) { + const OBTimer* const timer = timerList.top(); + + gettimeofday(&now, 0); + tm = timer->timeRemaining(now); + + timeout = &tm; + } + + select(xfd + 1, &rfds, 0, 0, timeout); + + // check for timer timeout + gettimeofday(&now, 0); + + // there is a small chance for deadlock here: + // *IF* the timer list keeps getting refreshed *AND* the time between + // timer->start() and timer->shouldFire() is within the timer's period + // then the timer will keep firing. This should be VERY near impossible. + while (! timerList.empty()) { + OBTimer *timer = timerList.top(); + if (! timer->shouldFire(now)) + break; + + timerList.pop(); + + timer->fireTimeout(); + timer->halt(); + if (timer->isRecurring()) + timer->start(); + } +} + + +void OBTimerQueueManager::addTimer(OBTimer *timer) +{ + assert(timer); + timerList.push(timer); +} + +void OBTimerQueueManager::removeTimer(OBTimer* timer) +{ + assert(timer); + timerList.release(timer); +} + +} diff --git a/otk/timer.hh b/otk/timer.hh new file mode 100644 index 00000000..2deeba58 --- /dev/null +++ b/otk/timer.hh @@ -0,0 +1,124 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +#ifndef _BLACKBOX_Timer_hh +#define _BLACKBOX_Timer_hh + +extern "C" { +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else // !TIME_WITH_SYS_TIME +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else // !HAVE_SYS_TIME_H +# include <time.h> +# endif // HAVE_SYS_TIME_H +#endif // TIME_WITH_SYS_TIME +} + +#include <queue> +#include <algorithm> +#include <vector> + +namespace otk { + +// forward declaration +class OBTimerQueueManager; + +typedef void *OBTimeoutData; +typedef void (*OBTimeoutHandler)(OBTimeoutData); + +class OBTimer { +private: + OBTimerQueueManager *manager; + OBTimeoutHandler handler; + OBTimeoutData data; + bool timing, recur; + + timeval _start, _timeout; + + OBTimer(const OBTimer&); + OBTimer& operator=(const OBTimer&); + +public: + OBTimer(OBTimerQueueManager *m, OBTimeoutHandler h, OBTimeoutData d); + virtual ~OBTimer(); + + void fireTimeout(); + + inline bool isTiming() const { return timing; } + inline bool isRecurring() const { return recur; } + + inline const timeval &getTimeout() const { return _timeout; } + inline const timeval &getStartTime() const { return _start; } + + timeval timeRemaining(const timeval &tm) const; + bool shouldFire(const timeval &tm) const; + timeval endpoint() const; + + inline void recurring(bool b) { recur = b; } + + void setTimeout(long t); + void setTimeout(const timeval &t); + + void start(); // manager acquires timer + void stop(); // manager releases timer + void halt(); // halts the timer + + bool operator<(const OBTimer& other) const + { return shouldFire(other.endpoint()); } +}; + + +template <class _Tp, class _Sequence, class _Compare> +class _timer_queue: protected std::priority_queue<_Tp, _Sequence, _Compare> { +public: + typedef std::priority_queue<_Tp, _Sequence, _Compare> _Base; + + _timer_queue(): _Base() {} + ~_timer_queue() {} + + void release(const _Tp& value) { + c.erase(std::remove(c.begin(), c.end(), value), c.end()); + // after removing the item we need to make the heap again + std::make_heap(c.begin(), c.end(), comp); + } + bool empty() const { return _Base::empty(); } + size_t size() const { return _Base::size(); } + void push(const _Tp& value) { _Base::push(value); } + void pop() { _Base::pop(); } + const _Tp& top() const { return _Base::top(); } +private: + // no copying! + _timer_queue(const _timer_queue&) {} + _timer_queue& operator=(const _timer_queue&) {} +}; + +struct TimerLessThan { + bool operator()(const OBTimer* const l, const OBTimer* const r) const { + return *r < *l; + } +}; + +typedef _timer_queue<OBTimer*, + std::vector<OBTimer*>, TimerLessThan> TimerQueue; + +class OBTimerQueueManager { +private: + TimerQueue timerList; +public: + OBTimerQueueManager() {} + virtual ~OBTimerQueueManager() {} + + //! Will wait for and fire the next timer in the queue. + /*! + The function will stop waiting if an event is received from the X server. + */ + virtual void fire(); + + virtual void addTimer(OBTimer* timer); + virtual void removeTimer(OBTimer* timer); +}; + +} + +#endif // _BLACKBOX_Timer_hh |
