summaryrefslogtreecommitdiff
path: root/otk
diff options
context:
space:
mode:
authorDana Jansens <danakj@orodu.net>2002-11-03 14:29:34 +0000
committerDana Jansens <danakj@orodu.net>2002-11-03 14:29:34 +0000
commit9259ec5732851dd66f7c598d629e3808ac7ab3d8 (patch)
tree5452b84b8937cde5f6977f26c24361cc1c0a5f08 /otk
parentad80ef0f667e3b72d9e35d7a93451a1e2dfa0ab6 (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.am19
-rw-r--r--otk/image.hh11
-rw-r--r--otk/imagecontrol.cc20
-rw-r--r--otk/timer.cc186
-rw-r--r--otk/timer.hh124
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