/**
* @file Timer.cc
* @author David Reveman <david@waimea.org>
* @date 05-Aug-2002 09:05:11
*
* @brief Implementation of Timer and Interrupt classes
*
* Timer implementation, used for delayed actions.
*
* Copyright (C) David Reveman. All rights reserved.
*
*/
#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;
/**
* @fn Timer(void)
* @brief Constructor for Timer class
*
* Sets SIGALRM signal handling and some initial values. Starts timer.
*
* @param wa Pointer to waimea object
*/
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;
Start();
}
/**
* @fn ~Timer(void)
* @brief Destructor for Timer class
*
* Removes all interrupts, stops timer and resets SIGALRM signal handling.
*/
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);
}
/**
* @fn AddInterrupt(Interrupt *i)
* @brief Adds interrupt to timer
*
* Inserts a new interrupt in the interrupt list and next timeout for the timer
* is updated if needed.
*
* @param i Interrupt that should be added
*/
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();
}
/**
* @fn Start(void)
* @brief Starts timer
*
* Starts timer or if timer is paused it continues timer.
*/
void Timer::Start(void) {
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);
}
}
/**
* @fn Pause(void)
* @brief Pause timer
*
* Stops timer but doesn't discard any interrupts. Call to Start function
* will unpauses timer.
*/
void Timer::Pause(void) {
struct itimerval remainval;
struct timeval elipsedval;
if (interrupts.empty() || paused) return;
paused = true;
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;
}
}
}
/**
* @fn ValidateInterrupts(XEvent *e)
* @brief Validates interrupt list
*
* Checks if the XEvent e invalidates any of the interrupts in the interrupt
* list, invalid interrupts are thrown away and the timers next timeout is
* updated if needed.
*
* @param e XEvent used for invalidation check
*/
void Timer::ValidateInterrupts(XEvent *e) {
if (interrupts.empty()) return;
Pause();
list<Interrupt *>::iterator it = interrupts.begin();
for (; it != interrupts.end(); ++it) {
list<int>::iterator dit = (*it)->action->delay_breaks->begin();
for (; dit != (*it)->action->delay_breaks->end(); ++dit) {
if (*dit == e->type &&
(*it)->event.xany.window == e->xany.window) {
interrupts.remove(*it);
it = interrupts.begin();
break;
}
}
}
Start();
}
/**
* @fn Interrupt(void)
* @brief Constructor for Interrupt class
*
* Creates an Interrupt that can be added to the timer.
*
* @param ac WaAction object, contains delay time
* @param e Event causing Interrupt creation
* @param win Window linked to Interrupt
*/
Interrupt::Interrupt(WaAction *ac, XEvent *e, Window win) {
memcpy(&event, e, sizeof(XEvent));
action = ac;
delay.tv_sec = ac->delay.tv_sec;
delay.tv_usec = ac->delay.tv_usec;
id = win;
}
/**
* @fn timeout(int signal)
* @brief Timeout handler function
*
* Handles the SIGALRM signal. Invokes actions for interrupt and updates
* timevalues for the interrupts.
*
* @param signal The signal we received
*/
void timeout(int signal) {
Interrupt *i = timer->interrupts.front();
timer->interrupts.pop_front();
list<Interrupt *>::iterator it = timer->interrupts.begin();
for (; it != timer->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 = timer->waimea->window_table.find(i->id)) !=
timer->waimea->window_table.end()) {
WindowObject *wo = (*wit).second;
switch (wo->type) {
case WindowType: {
WaWindow *wa = (WaWindow *) wo;
if (i->action->exec)
waexec(i->action->exec, wa->wascreen->displaystring);
else {
((*wa).*(i->action->winfunc))(&i->event, i->action);
XSync(wa->display, false);
}
} break;
case MenuTitleType:
case MenuItemType:
case MenuCBItemType:
case MenuSubType: {
WaMenuItem *wm = (WaMenuItem *) wo;
if (i->action->exec)
waexec(i->action->exec, wm->menu->wascreen->displaystring);
else {
((*wm).*(i->action->menufunc))(&i->event, i->action);
XSync(wm->menu->display, false);
}
} break;
case RootType: {
WaScreen *ws = (WaScreen *) wo;
if (i->action->exec)
waexec(i->action->exec, ws->displaystring);
else {
((*ws).*(i->action->rootfunc))(&i->event, i->action);
XSync(ws->display, false);
}
} break;
}
}
delete i;
timer->Start();
}
syntax highlighted by Code2HTML, v. 0.9.1