openbox/otk_c/timerqueue.c

99 lines
2.2 KiB
C
Raw Normal View History

// -*- 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);
}