/* Timer.cc
Copyright © 2003 David Reveman.
This file is part of Waimea.
Waimea is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Waimea is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with Waimea; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif // HAVE_CONFIG_H
#include "Timer.hh"
extern "C" {
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif // HAVE_SIGNAL_H
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif // HAVE_UNISTD_H
}
Timer *timer;
Timer::Timer(Waimea *wa) {
struct sigaction action;
timer = this;
waimea = wa;
timerval.it_interval.tv_sec = 0;
timerval.it_interval.tv_usec = 0;
timerval.it_value.tv_sec = 0;
timerval.it_value.tv_usec = 0;
action.sa_handler = timeout;
action.sa_mask = sigset_t();
action.sa_flags = 0;
sigaction(SIGALRM, &action, NULL);
paused = true;
timer_signal = 0;
start();
}
Timer::~Timer(void) {
struct sigaction action;
action.sa_handler = SIG_DFL;
action.sa_mask = sigset_t();
action.sa_flags = 0;
timerval.it_value.tv_sec = 0;
timerval.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &timerval, NULL);
sigaction(SIGALRM, &action, NULL);
LISTDEL(interrupts);
}
void Timer::addInterrupt(Interrupt *i) {
pause();
if (interrupts.empty())
interrupts.push_back(i);
else {
list<Interrupt *>::iterator it = interrupts.begin();
for (; it != interrupts.end(); ++it) {
if (i->delay.tv_sec < (*it)->delay.tv_sec ||
(i->delay.tv_sec == (*it)->delay.tv_sec &&
i->delay.tv_usec < (*it)->delay.tv_usec)) {
interrupts.insert(it, i);
break;
}
}
if (it == interrupts.end())
interrupts.push_back(i);
}
start();
}
void Timer::start(void) {
if (! paused) pause();
if (! interrupts.empty()) {
timerval.it_value.tv_sec = interrupts.front()->delay.tv_sec;
timerval.it_value.tv_usec = interrupts.front()->delay.tv_usec;
if (timerval.it_value.tv_sec < 0) timerval.it_value.tv_sec = 0;
if (timerval.it_value.tv_usec < 0) timerval.it_value.tv_usec = 0;
if (timerval.it_value.tv_sec == 0 && timerval.it_value.tv_usec == 0)
timerval.it_value.tv_usec = 1;
paused = false;
setitimer(ITIMER_REAL, &timerval, NULL);
}
}
void Timer::pause(void) {
struct itimerval remainval;
struct timeval elipsedval;
if (interrupts.empty() || paused) {
paused = true;
return;
}
timerval.it_value.tv_sec = 0;
timerval.it_value.tv_usec = 0;
getitimer(ITIMER_REAL, &remainval);
setitimer(ITIMER_REAL, &timerval, NULL);
elipsedval.tv_sec = interrupts.front()->delay.tv_sec -
remainval.it_value.tv_sec;
elipsedval.tv_usec = interrupts.front()->delay.tv_usec -
remainval.it_value.tv_usec;
if (elipsedval.tv_usec < 0) {
elipsedval.tv_sec--;
elipsedval.tv_usec += 1000000;
}
list<Interrupt *>::iterator it = interrupts.begin();
for (; it != interrupts.end(); ++it) {
(*it)->delay.tv_sec -= elipsedval.tv_sec;
(*it)->delay.tv_usec -= elipsedval.tv_usec;
if ((*it)->delay.tv_usec < 0) {
(*it)->delay.tv_sec--;
(*it)->delay.tv_usec += 1000000;
}
}
}
void Timer::removeInterrupt(int id) {
pause();
if (interrupts.empty()) return;
list<Interrupt *>::iterator it = interrupts.begin();
for (; it != interrupts.end(); ++it) {
if ((*it)->ident == id) {
delete *it;
it = interrupts.erase(it);
}
}
start();
}
bool Timer::exitsInterrupt(int id) {
bool exits = false;
pause();
if (interrupts.empty()) return false;
list<Interrupt *>::iterator it = interrupts.begin();
for (; it != interrupts.end(); ++it) {
if ((*it)->ident == id) {
exits = true;
break;
}
}
start();
return exits;
}
Interrupt::Interrupt(Action *ac, XEvent *e, Window win) {
memcpy(&event, e, sizeof(XEvent));
action = ac->ref();
delay.tv_sec = ac->delay / 1000;
delay.tv_usec = (ac->delay % 1000) * 1000;
window = win;
ident = ac->timer_id;
}
Interrupt::~Interrupt(void) {
action->unref();
}
void Timer::handleTimeout(void) {
if (interrupts.empty()) return;
Interrupt *i = interrupts.front();
if (! i) return;
interrupts.pop_front();
list<Interrupt *>::iterator it = interrupts.begin();
for (; it != interrupts.end(); ++it) {
(*it)->delay.tv_sec -= i->delay.tv_sec;
(*it)->delay.tv_usec -= i->delay.tv_usec;
if ((*it)->delay.tv_usec < 0) {
(*it)->delay.tv_sec--;
(*it)->delay.tv_usec += 1000000;
}
}
map<Window, WindowObject *>::iterator wit;
if ((wit = waimea->window_table.find(i->window)) !=
waimea->window_table.end()) {
AWindowObject *awo = (AWindowObject *) (*wit).second;
((*awo).*(i->action->func))(&i->event, i->action);
}
if (i->action->periodic_timer) {
i->delay.tv_sec = i->action->delay / 1000;
i->delay.tv_usec = (i->action->delay % 1000) * 1000;
addInterrupt(i);
} else
delete i;
start();
}
void timeout(int signal) {
timer->timer_signal = signal;
}
syntax highlighted by Code2HTML, v. 0.9.1