summaryrefslogtreecommitdiff
path: root/otk_c/timerqueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'otk_c/timerqueue.c')
-rw-r--r--otk_c/timerqueue.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/otk_c/timerqueue.c b/otk_c/timerqueue.c
new file mode 100644
index 00000000..25fd8501
--- /dev/null
+++ b/otk_c/timerqueue.c
@@ -0,0 +1,98 @@
+// -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
+
+#include "../config.h"
+#include "timerqueue.h"
+#include "display.h"
+
+#include <X11/Xlib.h>
+#include <Python.h>
+
+static PyObject *list = NULL; // PyListObject
+
+void OtkTimerQueue_Initialize()
+{
+ list = PyList_New(0);
+}
+
+void OtkTimerQueue_Add(OtkTimer* timer)
+{
+ PyList_Append(list, (PyObject*)timer);
+ PyList_Sort(list);
+}
+
+void OtkTimerQueue_Remove(OtkTimer* timer)
+{
+ int index;
+
+ index = PySequence_Index(list, (PyObject*)timer);
+ if (index >= 0)
+ PySequence_DelItem(list, index);
+}
+
+static Bool shouldFire(OtkTimer *timer, const struct timeval *now)
+{
+ return ! ((now->tv_sec < timer->end.tv_sec) ||
+ (now->tv_sec == timer->end.tv_sec &&
+ now->tv_usec < timer->end.tv_usec));
+}
+
+static void normalizeTimeval(struct timeval *time)
+{
+ while (time->tv_usec < 0) {
+ if (time->tv_sec > 0) {
+ --time->tv_sec;
+ time->tv_usec += 1000000;
+ } else {
+ time->tv_usec = 0;
+ }
+ }
+
+ if (time->tv_usec >= 1000000) {
+ time->tv_sec += time->tv_usec / 1000000;
+ time->tv_usec %= 1000000;
+ }
+
+ if (time->tv_sec < 0) time->tv_sec = 0;
+}
+
+void OtkTimerQueue_Fire()
+{
+ fd_set rfds;
+ struct timeval now, tm, *timeout = NULL;
+
+ const int xfd = ConnectionNumber(OBDisplay->display);
+
+ FD_ZERO(&rfds);
+ FD_SET(xfd, &rfds); // break on any x events
+
+ // 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 (PyList_Size(list)) {
+ OtkTimer *timer = (OtkTimer*)PyList_GetItem(list, 0);
+
+ if (! shouldFire(timer, &now)) {
+ tm.tv_sec = timer->end.tv_sec - now.tv_sec;
+ tm.tv_usec = timer->end.tv_usec - now.tv_usec;
+ normalizeTimeval(&tm);
+ timeout = &tm; // set the timeout for the select
+ break; // go on and wait
+ }
+
+ // stop and remove the timer from the queue
+ PySequence_DelItem(list, 0);
+ timer->timing = False;
+
+ if (timer->handler)
+ timer->handler(timer->data);
+
+ if (timer->recur)
+ OtkTimer_Start(timer);
+ }
+
+ select(xfd + 1, &rfds, 0, 0, timeout);
+}