1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 04:20:27 +01:00

- moved WINGs's internal handlers (timer, idle and input) to handlers.c

to avoid code duplication.
- simplified wevent.c and wutil.c
- renamed WMAddEternalTimerHandler() to WMAddPersistentTimerHandler()
This commit is contained in:
dan
2001-03-20 23:46:57 +00:00
parent dd9fd9f12a
commit f5dcab0663
8 changed files with 678 additions and 1189 deletions

View File

@@ -4,7 +4,9 @@ Changes since wmaker 0.64.0:
- made programmatic scroller changes send notifications
- replaced WMSetBoxExpandsToParent with WMSetViewExpands...
- added WMGetLabelFont()
- added WMAddEternalTimerHandler()
- added WMAddPersistentTimerHandler()
- Moved all internal handlers (timer, idle and input) to handlers.c
- simplified wevent.c and wutil.c.
changes since wmaker 0.63.1:
............................

View File

@@ -29,6 +29,7 @@ libWINGs_a_SOURCES = \
dragsource.c \
error.c \
findfile.c \
handlers.c \
hashtable.c \
host.c \
international.c \
@@ -81,6 +82,7 @@ libWUtil_a_SOURCES = \
data.c \
error.c \
findfile.c \
handlers.c \
hashtable.c \
host.c \
international.c \

View File

@@ -658,8 +658,8 @@ void WMMaskEvent(Display *dpy, long mask, XEvent *event);
WMHandlerID WMAddTimerHandler(int milliseconds, WMCallback *callback,
void *cdata);
WMHandlerID WMAddEternalTimerHandler(int milliseconds, WMCallback *callback,
void *cdata);
WMHandlerID WMAddPersistentTimerHandler(int milliseconds, WMCallback *callback,
void *cdata);
void WMDeleteTimerWithClientData(void *cdata);

View File

@@ -538,6 +538,14 @@ void W_BalloonHandleEnterView(WMView *view);
void W_BalloonHandleLeaveView(WMView *view);
Bool W_CheckIdleHandlers(void);
void W_CheckTimerHandlers(void);
Bool W_HaveInputHandlers(void);
Bool W_HandleInputEvents(Bool waitForInput, int inputfd);
#ifdef __cplusplus
}
#endif /* __cplusplus */

644
WINGs/handlers.c Normal file
View File

@@ -0,0 +1,644 @@
/*
* WINGs internal handlers: timer, idle and input handlers
*/
#include "WINGsP.h"
#include "../src/config.h"
#include <sys/types.h>
#include <unistd.h>
#include <X11/Xos.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include <time.h>
#ifndef X_GETTIMEOFDAY
#define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
#endif
typedef struct TimerHandler {
WMCallback *callback; /* procedure to call */
struct timeval when; /* when to call the callback */
void *clientData;
struct TimerHandler *next;
int nextDelay; /* 0 if it's one-shot */
} TimerHandler;
typedef struct IdleHandler {
WMCallback *callback;
void *clientData;
} IdleHandler;
typedef struct InputHandler {
WMInputProc *callback;
void *clientData;
int fd;
int mask;
} InputHandler;
/* queue of timer event handlers */
static TimerHandler *timerHandler=NULL;
static WMBag *idleHandler=NULL;
static WMBag *inputHandler=NULL;
// this should go to wevent.c and wutil.c too
#define timerPending() (timerHandler)
static void
rightNow(struct timeval *tv) {
X_GETTIMEOFDAY(tv);
}
/* is t1 after t2 ? */
#define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
(((t1).tv_sec == (t2).tv_sec) \
&& ((t1).tv_usec > (t2).tv_usec)))
#define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
#define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
static void
addmillisecs(struct timeval *tv, int milliseconds)
{
tv->tv_usec += milliseconds*1000;
tv->tv_sec += tv->tv_usec/1000000;
tv->tv_usec = tv->tv_usec%1000000;
}
static void
enqueueTimerHandler(TimerHandler *handler)
{
TimerHandler *tmp;
/* insert callback in queue, sorted by time left */
if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
/* first in the queue */
handler->next = timerHandler;
timerHandler = handler;
} else {
tmp = timerHandler;
while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
tmp = tmp->next;
}
handler->next = tmp->next;
tmp->next = handler;
}
}
static void
delayUntilNextTimerEvent(struct timeval *delay)
{
struct timeval now;
TimerHandler *handler;
handler = timerHandler;
while (handler && IS_ZERO(handler->when)) handler = handler->next;
if (!handler) {
/* The return value of this function is only valid if there _are_
timers active. */
delay->tv_sec = 0;
delay->tv_usec = 0;
return;
}
rightNow(&now);
if (IS_AFTER(now, handler->when)) {
delay->tv_sec = 0;
delay->tv_usec = 0;
} else {
delay->tv_sec = handler->when.tv_sec - now.tv_sec;
delay->tv_usec = handler->when.tv_usec - now.tv_usec;
if (delay->tv_usec < 0) {
delay->tv_usec += 1000000;
delay->tv_sec--;
}
}
}
WMHandlerID
WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
{
TimerHandler *handler;
handler = malloc(sizeof(TimerHandler));
if (!handler)
return NULL;
rightNow(&handler->when);
addmillisecs(&handler->when, milliseconds);
handler->callback = callback;
handler->clientData = cdata;
handler->nextDelay = 0;
enqueueTimerHandler(handler);
return handler;
}
WMHandlerID
WMAddPersistentTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
{
TimerHandler *handler = WMAddTimerHandler(milliseconds, callback, cdata);
if (handler != NULL)
handler->nextDelay = milliseconds;
return handler;
}
void
WMDeleteTimerWithClientData(void *cdata)
{
TimerHandler *handler, *tmp;
if (!cdata || !timerHandler)
return;
tmp = timerHandler;
if (tmp->clientData==cdata) {
tmp->nextDelay = 0;
if (!IS_ZERO(tmp->when)) {
timerHandler = tmp->next;
wfree(tmp);
}
} else {
while (tmp->next) {
if (tmp->next->clientData==cdata) {
handler = tmp->next;
handler->nextDelay = 0;
if (IS_ZERO(handler->when))
break;
tmp->next = handler->next;
wfree(handler);
break;
}
tmp = tmp->next;
}
}
}
void
WMDeleteTimerHandler(WMHandlerID handlerID)
{
TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
if (!handler || !timerHandler)
return;
tmp = timerHandler;
handler->nextDelay = 0;
if (IS_ZERO(handler->when))
return;
if (tmp==handler) {
timerHandler = handler->next;
wfree(handler);
} else {
while (tmp->next) {
if (tmp->next==handler) {
tmp->next=handler->next;
wfree(handler);
break;
}
tmp = tmp->next;
}
}
}
WMHandlerID
WMAddIdleHandler(WMCallback *callback, void *cdata)
{
IdleHandler *handler;
handler = malloc(sizeof(IdleHandler));
if (!handler)
return NULL;
handler->callback = callback;
handler->clientData = cdata;
/* add handler at end of queue */
if (!idleHandler) {
idleHandler = WMCreateBag(16);
}
WMPutInBag(idleHandler, handler);
return handler;
}
void
WMDeleteIdleHandler(WMHandlerID handlerID)
{
IdleHandler *handler = (IdleHandler*)handlerID;
int pos;
if (!handler || !idleHandler)
return;
pos = WMGetFirstInBag(idleHandler, handler);
if (pos != WBNotFound) {
wfree(handler);
WMDeleteFromBag(idleHandler, pos);
}
}
WMHandlerID
WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
{
InputHandler *handler;
handler = wmalloc(sizeof(InputHandler));
handler->fd = fd;
handler->mask = condition;
handler->callback = proc;
handler->clientData = clientData;
if (!inputHandler)
inputHandler = WMCreateBag(16);
WMPutInBag(inputHandler, handler);
return handler;
}
void
WMDeleteInputHandler(WMHandlerID handlerID)
{
InputHandler *handler = (InputHandler*)handlerID;
int pos;
if (!handler || !inputHandler)
return;
pos = WMGetFirstInBag(inputHandler, handler);
if (pos != WBNotFound) {
wfree(handler);
WMDeleteFromBag(inputHandler, pos);
}
}
Bool
W_CheckIdleHandlers(void)
{
IdleHandler *handler;
WMBag *handlerCopy;
WMBagIterator iter;
if (!idleHandler || WMGetBagItemCount(idleHandler)==0) {
W_FlushIdleNotificationQueue();
/* make sure an observer in queue didn't added an idle handler */
return (idleHandler!=NULL && WMGetBagItemCount(idleHandler)>0);
}
handlerCopy = WMCreateBag(WMGetBagItemCount(idleHandler));
WMAppendBag(handlerCopy, idleHandler);
for (handler = WMBagFirst(handlerCopy, &iter);
iter != NULL;
handler = WMBagNext(handlerCopy, &iter)) {
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(idleHandler, handler) == WBNotFound)
continue;
(*handler->callback)(handler->clientData);
WMDeleteIdleHandler(handler);
}
WMFreeBag(handlerCopy);
W_FlushIdleNotificationQueue();
/* this is not necesarrily False, because one handler can re-add itself */
return (WMGetBagItemCount(idleHandler)>0);
}
void
W_CheckTimerHandlers(void)
{
TimerHandler *handler;
struct timeval now;
if (!timerHandler) {
W_FlushASAPNotificationQueue();
return;
}
rightNow(&now);
handler = timerHandler;
while (handler && IS_AFTER(now, handler->when)) {
if (!IS_ZERO(handler->when)) {
SET_ZERO(handler->when);
(*handler->callback)(handler->clientData);
}
handler = handler->next;
}
while (timerHandler && IS_ZERO(timerHandler->when)) {
handler = timerHandler;
timerHandler = timerHandler->next;
if (handler->nextDelay > 0) {
handler->when = now;
addmillisecs(&handler->when, handler->nextDelay);
enqueueTimerHandler(handler);
} else {
wfree(handler);
}
}
W_FlushASAPNotificationQueue();
}
Bool
W_HaveInputHandlers(void)
{
return (inputHandler && WMGetBagItemCount(inputHandler)>0);
}
/*
* This functions will handle input events on all registered file descriptors.
* Input:
* - waitForInput - True if we want the function to wait until an event
* appears on a file descriptor we watch, False if we
* want the function to immediately return if there is
* no data available on the file descriptors we watch.
* - inputfd - Extra input file descriptor to watch for input.
* This is only used when called from wevent.c to watch
* on ConnectionNumber(dpy) to avoid blocking of X events
* if we wait for input from other file handlers.
* Output:
* if waitForInput is False, the function will return False if there are no
* input handlers registered, or if there is no data
* available on the registered ones, and will return True
* if there is at least one input handler that has data
* available.
* if waitForInput is True, the function will return False if there are no
* input handlers registered, else it will block until an
* event appears on one of the file descriptors it watches
* and then it will return True.
*
* If the retured value is True, the input handlers for the corresponding file
* descriptors are also called.
*
* Parametersshould be passed like this:
* - from wevent.c:
* waitForInput = True
* inputfd = ConnectionNumber(dpy)
* - from wutil.c:
* waitForInput - value passed from the function who calls this function
* inputfd = -1
*
*/
Bool
W_HandleInputEvents(Bool waitForInput, int inputfd)
{
#if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
struct poll fd *fds;
InputHandler *handler;
int count, timeout, nfds, i, extrafd, retval;
extrafd = (inputfd < 0) ? 0 : 1;
if (inputHandler)
nfds = WMGetBagItemCount(inputHandler);
else
nfds = 0;
if (!extrafd && nfds==0) {
W_FlushASAPNotificationQueue();
return False;
}
fds = wmalloc((nfds+extrafd) * sizeof(struct pollfd));
if (extrafd) {
/* put this to the end of array to avoid using ranges from 1 to nfds+1 */
fds[nfds].fd = inputfd;
fds[nfds].events = POLLIN;
}
for (i = 0; i<nfds; i++) {
handler = WMGetFromBag(inputHandler, i);
fds[i].fd = handler->fd;
fds[i].events = 0;
if (handler->mask & WIReadMask)
fds[i].events |= POLLIN;
if (handler->mask & WIWriteMask)
fds[i].events |= POLLOUT;
#if 0 /* FIXME */
if (handler->mask & WIExceptMask)
FD_SET(handler->fd, &eset);
#endif
}
/*
* Setup the timeout to the estimated time until the
* next timer expires.
*/
if (!waitForInput) {
timeout = 0;
} else if (timerPending()) {
struct timeval tv;
delayUntilNextTimerEvent(&tv);
timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
} else {
timeout = -1;
}
count = poll(fds, nfds+extrafd, timeout);
if (count>0 && nfds>0) {
WMBag *handlerCopy = WMCreateBag(nfds);
for (i=0; i<nfds; i++)
WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
for (i=0; i<nfds; i++) {
int mask;
handler = WMGetFromBag(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
continue;
mask = 0;
if ((handler->mask & WIReadMask) &&
(fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
mask |= WIReadMask;
if ((handler->mask & WIWriteMask) &&
(fds[i].revents & (POLLOUT | POLLWRBAND)))
mask |= WIWriteMask;
if ((handler->mask & WIExceptMask) &&
(fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
mask |= WIExceptMask;
if (mask!=0 && handler->callback) {
(*handler->callback)(handler->fd, mask,
handler->clientData);
}
}
WMFreeBag(handlerCopy);
}
/* we may only return count>0, because the returned value is not checked
* anywhere anyway. -Dan
*/
retval = ((inputfd < 0) ? (count > 0) :
fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI));
wfree(fds);
W_FlushASAPNotificationQueue();
return retval;
#else
#ifdef HAVE_SELECT
struct timeval timeout;
struct timeval *timeoutPtr;
fd_set rset, wset, eset;
int maxfd, nfds, i;
int count;
InputHandler *handler;
if (inputHandler)
nfds = WMGetBagItemCount(inputHandler);
else
nfds = 0;
if (inputfd<0 && nfds==0) {
W_FlushASAPNotificationQueue();
return False;
}
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
if (inputfd < 0) {
maxfd = 0;
} else {
FD_SET(inputfd, &rset);
maxfd = inputfd;
}
for (i=0; i<nfds; i++) {
handler = WMGetFromBag(inputHandler, i);
if (handler->mask & WIReadMask)
FD_SET(handler->fd, &rset);
if (handler->mask & WIWriteMask)
FD_SET(handler->fd, &wset);
if (handler->mask & WIExceptMask)
FD_SET(handler->fd, &eset);
if (maxfd < handler->fd)
maxfd = handler->fd;
}
/*
* Setup the timeout to the estimated time until the
* next timer expires.
*/
if (!waitForInput) {
SET_ZERO(timeout);
timeoutPtr = &timeout;
} else if (timerPending()) {
delayUntilNextTimerEvent(&timeout);
timeoutPtr = &timeout;
} else {
timeoutPtr = (struct timeval*)0;
}
count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
if (count>0 && nfds>0) {
WMBag *handlerCopy = WMCreateBag(nfds);
for (i=0; i<nfds; i++)
WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
for (i=0; i<nfds; i++) {
int mask;
handler = WMGetFromBag(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
continue;
mask = 0;
if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
mask |= WIReadMask;
if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
mask |= WIWriteMask;
if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
mask |= WIExceptMask;
if (mask!=0 && handler->callback) {
(*handler->callback)(handler->fd, mask,
handler->clientData);
}
}
WMFreeBag(handlerCopy);
}
W_FlushASAPNotificationQueue();
return ((inputfd < 0) ? (count > 0) : FD_ISSET(inputfd, &rset));
#else /* not HAVE_SELECT, not HAVE_POLL */
Neither select nor poll. You lose.
#endif /* HAVE_SELECT */
#endif /* HAVE_POLL */
}

View File

@@ -6,55 +6,6 @@
#include "WINGsP.h"
#include "../src/config.h"
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <X11/Xos.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include <time.h>
#ifndef X_GETTIMEOFDAY
#define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
#endif
typedef struct TimerHandler {
WMCallback *callback; /* procedure to call */
struct timeval when; /* when to call the callback */
void *clientData;
struct TimerHandler *next;
int nextDelay; /* 0 if it's one-shot */
} TimerHandler;
typedef struct IdleHandler {
WMCallback *callback;
void *clientData;
} IdleHandler;
typedef struct InputHandler {
WMInputProc *callback;
void *clientData;
int fd;
int mask;
} InputHandler;
/* table to map event types to event masks */
static unsigned long eventMasks[] = {
@@ -100,355 +51,13 @@ static unsigned long eventMasks[] = {
/* queue of timer event handlers */
static TimerHandler *timerHandler=NULL;
static WMBag *idleHandler=NULL;
static WMBag *inputHandler=NULL;
/* hook for other toolkits or wmaker process their events */
static WMEventHook *extraEventHandler=NULL;
#define timerPending() (timerHandler)
static void
rightNow(struct timeval *tv) {
X_GETTIMEOFDAY(tv);
}
/* is t1 after t2 ? */
#define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
(((t1).tv_sec == (t2).tv_sec) \
&& ((t1).tv_usec > (t2).tv_usec)))
#define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
#define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
static void
addmillisecs(struct timeval *tv, int milliseconds)
{
tv->tv_usec += milliseconds*1000;
tv->tv_sec += tv->tv_usec/1000000;
tv->tv_usec = tv->tv_usec%1000000;
}
static void
enqueueTimerHandler(TimerHandler *handler)
{
TimerHandler *tmp;
/* insert callback in queue, sorted by time left */
if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
/* first in the queue */
handler->next = timerHandler;
timerHandler = handler;
} else {
tmp = timerHandler;
while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
tmp = tmp->next;
}
handler->next = tmp->next;
tmp->next = handler;
}
}
WMHandlerID
WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
{
TimerHandler *handler;
handler = malloc(sizeof(TimerHandler));
if (!handler)
return NULL;
rightNow(&handler->when);
addmillisecs(&handler->when, milliseconds);
handler->callback = callback;
handler->clientData = cdata;
handler->nextDelay = 0;
enqueueTimerHandler(handler);
return handler;
}
WMHandlerID
WMAddEternalTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
{
TimerHandler *handler = WMAddTimerHandler(milliseconds, callback, cdata);
if (handler != NULL)
handler->nextDelay = milliseconds;
return handler;
}
void
WMDeleteTimerWithClientData(void *cdata)
{
TimerHandler *handler, *tmp;
if (!cdata || !timerHandler)
return;
tmp = timerHandler;
if (tmp->clientData==cdata) {
tmp->nextDelay = 0;
if (!IS_ZERO(tmp->when)) {
timerHandler = tmp->next;
wfree(tmp);
}
} else {
while (tmp->next) {
if (tmp->next->clientData==cdata) {
handler = tmp->next;
handler->nextDelay = 0;
if (IS_ZERO(handler->when))
break;
tmp->next = handler->next;
wfree(handler);
break;
}
tmp = tmp->next;
}
}
}
void
WMDeleteTimerHandler(WMHandlerID handlerID)
{
TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
if (!handler || !timerHandler)
return;
tmp = timerHandler;
handler->nextDelay = 0;
if (IS_ZERO(handler->when))
return;
if (tmp==handler) {
timerHandler = handler->next;
wfree(handler);
} else {
while (tmp->next) {
if (tmp->next==handler) {
tmp->next=handler->next;
wfree(handler);
break;
}
tmp = tmp->next;
}
}
}
WMHandlerID
WMAddIdleHandler(WMCallback *callback, void *cdata)
{
IdleHandler *handler;
handler = malloc(sizeof(IdleHandler));
if (!handler)
return NULL;
handler->callback = callback;
handler->clientData = cdata;
/* add handler at end of queue */
if (!idleHandler) {
idleHandler = WMCreateBag(16);
}
WMPutInBag(idleHandler, handler);
return handler;
}
void
WMDeleteIdleHandler(WMHandlerID handlerID)
{
IdleHandler *handler = (IdleHandler*)handlerID;
int pos;
if (!handler || !idleHandler)
return;
pos = WMGetFirstInBag(idleHandler, handler);
if (pos != WBNotFound) {
wfree(handler);
WMDeleteFromBag(idleHandler, pos);
}
}
WMHandlerID
WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
{
InputHandler *handler;
handler = wmalloc(sizeof(InputHandler));
handler->fd = fd;
handler->mask = condition;
handler->callback = proc;
handler->clientData = clientData;
if (!inputHandler)
inputHandler = WMCreateBag(16);
WMPutInBag(inputHandler, handler);
return handler;
}
void
WMDeleteInputHandler(WMHandlerID handlerID)
{
InputHandler *handler = (InputHandler*)handlerID;
int pos;
if (!handler || !inputHandler)
return;
pos = WMGetFirstInBag(inputHandler, handler);
if (pos != WBNotFound) {
wfree(handler);
WMDeleteFromBag(inputHandler, pos);
}
}
static Bool
checkIdleHandlers()
{
IdleHandler *handler;
WMBag *handlerCopy;
WMBagIterator iter;
if (!idleHandler || WMGetBagItemCount(idleHandler)==0) {
W_FlushIdleNotificationQueue();
/* make sure an observer in queue didn't added an idle handler */
return (idleHandler!=NULL && WMGetBagItemCount(idleHandler)>0);
}
handlerCopy = WMCreateBag(WMGetBagItemCount(idleHandler));
WMAppendBag(handlerCopy, idleHandler);
for (handler = WMBagFirst(handlerCopy, &iter);
iter != NULL;
handler = WMBagNext(handlerCopy, &iter)) {
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(idleHandler, handler) == WBNotFound)
continue;
(*handler->callback)(handler->clientData);
WMDeleteIdleHandler(handler);
}
WMFreeBag(handlerCopy);
W_FlushIdleNotificationQueue();
/* this is not necesarrily False, because one handler can re-add itself */
return (WMGetBagItemCount(idleHandler)>0);
}
static void
checkTimerHandlers()
{
TimerHandler *handler;
struct timeval now;
if (!timerHandler) {
W_FlushASAPNotificationQueue();
return;
}
rightNow(&now);
handler = timerHandler;
while (handler && IS_AFTER(now, handler->when)) {
if (!IS_ZERO(handler->when)) {
SET_ZERO(handler->when);
(*handler->callback)(handler->clientData);
}
handler = handler->next;
}
while (timerHandler && IS_ZERO(timerHandler->when)) {
handler = timerHandler;
timerHandler = timerHandler->next;
if (handler->nextDelay > 0) {
handler->when = now;
addmillisecs(&handler->when, handler->nextDelay);
enqueueTimerHandler(handler);
} else {
wfree(handler);
}
}
W_FlushASAPNotificationQueue();
}
static void
delayUntilNextTimerEvent(struct timeval *delay)
{
struct timeval now;
TimerHandler *handler;
handler = timerHandler;
while (handler && IS_ZERO(handler->when)) handler = handler->next;
if (!handler) {
/* The return value of this function is only valid if there _are_
timers active. */
delay->tv_sec = 0;
delay->tv_usec = 0;
return;
}
rightNow(&now);
if (IS_AFTER(now, handler->when)) {
delay->tv_sec = 0;
delay->tv_usec = 0;
} else {
delay->tv_sec = handler->when.tv_sec - now.tv_sec;
delay->tv_usec = handler->when.tv_usec - now.tv_usec;
if (delay->tv_usec < 0) {
delay->tv_usec += 1000000;
delay->tv_sec--;
}
}
}
/*
* WMCreateEventHandler--
* Create an event handler and put it in the event handler list for the
@@ -775,153 +384,6 @@ WMIsDoubleClick(XEvent *event)
Bool
W_WaitForEvent(Display *dpy, unsigned long xeventmask)
{
#if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
struct pollfd *fds;
InputHandler *handler;
int count, timeout, nfds, i, retval;
if (inputHandler)
nfds = WMGetBagItemCount(inputHandler);
else
nfds = 0;
fds = wmalloc(nfds+1 * sizeof(struct pollfd));
/* put this to the end of array to avoid using ranges from 1 to nfds+1 */
fds[nfds].fd = ConnectionNumber(dpy);
fds[nfds].events = POLLIN;
for (i = 0; i<nfds; i++) {
handler = WMGetFromBag(inputHandler, i);
fds[i].fd = handler->fd;
fds[i].events = 0;
if (handler->mask & WIReadMask)
fds[i].events |= POLLIN;
if (handler->mask & WIWriteMask)
fds[i].events |= POLLOUT;
#if 0 /* FIXME */
if (handler->mask & WIExceptMask)
FD_SET(handler->fd, &eset);
#endif
}
/*
* Setup the select() timeout to the estimated time until the
* next timer expires.
*/
if (timerPending()) {
struct timeval tv;
delayUntilNextTimerEvent(&tv);
timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
} else {
timeout = -1;
}
if (xeventmask==0) {
if (XPending(dpy))
return True;
} else {
XEvent ev;
if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
XPutBackEvent(dpy, &ev);
return True;
}
}
count = poll(fds, nfds, timeout);
if (count>0 && nfds>0) {
WMBag *handlerCopy = WMCreateBag(nfds);
for (i=0; i<nfds; i++)
WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
for (i=0; i<nfds; i++) {
int mask;
handler = WMGetFromBag(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
continue;
mask = 0;
if ((handler->mask & WIReadMask) &&
(fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
mask |= WIReadMask;
if ((handler->mask & WIWriteMask) &&
(fds[i].revents & (POLLOUT | POLLWRBAND)))
mask |= WIWriteMask;
if ((handler->mask & WIExceptMask) &&
(fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
mask |= WIExceptMask;
if (mask!=0 && handler->callback) {
(*handler->callback)(handler->fd, mask,
handler->clientData);
}
}
WMFreeBag(handlerCopy);
}
retval = fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
wfree(fds);
W_FlushASAPNotificationQueue();
return retval;
#else /* not HAVE_POLL */
#ifdef HAVE_SELECT
struct timeval timeout;
struct timeval *timeoutPtr;
fd_set rset, wset, eset;
int maxfd, nfds, i;
int count;
InputHandler *handler;
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
FD_SET(ConnectionNumber(dpy), &rset);
maxfd = ConnectionNumber(dpy);
if (inputHandler)
nfds = WMGetBagItemCount(inputHandler);
else
nfds = 0;
for (i=0; i<nfds; i++) {
handler = WMGetFromBag(inputHandler, i);
if (handler->mask & WIReadMask)
FD_SET(handler->fd, &rset);
if (handler->mask & WIWriteMask)
FD_SET(handler->fd, &wset);
if (handler->mask & WIExceptMask)
FD_SET(handler->fd, &eset);
if (maxfd < handler->fd)
maxfd = handler->fd;
}
/*
* Setup the select() timeout to the estimated time until the
* next timer expires.
*/
if (timerPending()) {
delayUntilNextTimerEvent(&timeout);
timeoutPtr = &timeout;
} else {
timeoutPtr = (struct timeval*)0;
}
XSync(dpy, False);
if (xeventmask==0) {
if (XPending(dpy))
@@ -934,49 +396,7 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask)
}
}
count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
if (count>0 && nfds>0) {
WMBag *handlerCopy = WMCreateBag(nfds);
for (i=0; i<nfds; i++)
WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
for (i=0; i<nfds; i++) {
int mask;
handler = WMGetFromBag(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
continue;
mask = 0;
if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
mask |= WIReadMask;
if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
mask |= WIWriteMask;
if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
mask |= WIExceptMask;
if (mask!=0 && handler->callback) {
(*handler->callback)(handler->fd, mask,
handler->clientData);
}
}
WMFreeBag(handlerCopy);
}
W_FlushASAPNotificationQueue();
return FD_ISSET(ConnectionNumber(dpy), &rset);
#else /* not HAVE_SELECT, not HAVE_POLL */
Neither select nor poll. You lose.
#endif /* HAVE_SELECT */
#endif /* HAVE_POLL */
return W_HandleInputEvents(True, ConnectionNumber(dpy));
}
@@ -984,14 +404,14 @@ void
WMNextEvent(Display *dpy, XEvent *event)
{
/* Check any expired timers */
checkTimerHandlers();
W_CheckTimerHandlers();
while (XPending(dpy) == 0) {
/* Do idle stuff */
/* Do idle and timer stuff while there are no timer or X events */
while (XPending(dpy) == 0 && checkIdleHandlers()) {
while (XPending(dpy) == 0 && W_CheckIdleHandlers()) {
/* dispatch timer events */
checkTimerHandlers();
W_CheckTimerHandlers();
}
/*
@@ -1003,54 +423,12 @@ WMNextEvent(Display *dpy, XEvent *event)
W_WaitForEvent(dpy, 0);
/* Check any expired timers */
checkTimerHandlers();
W_CheckTimerHandlers();
}
XNextEvent(dpy, event);
}
#if 0
void
WMMaskEvent(Display *dpy, long mask, XEvent *event)
{
unsigned long milliseconds;
struct timeval timeout;
struct timeval *timeoutOrInfty;
fd_set readset;
while (!XCheckMaskEvent(dpy, mask, event)) {
/* Do idle stuff while there are no timer or X events */
while (checkIdleHandlers()) {
if (XCheckMaskEvent(dpy, mask, event))
return;
}
/*
* Setup the select() timeout to the estimated time until the
* next timer expires.
*/
if (timerPending()) {
delayUntilNextTimerEvent(&timeout);
timeoutOrInfty = &timeout;
} else {
timeoutOrInfty = (struct timeval*)0;
}
if (XCheckMaskEvent(dpy, mask, event))
return;
/* Wait for input on the X connection socket */
FD_ZERO(&readset);
FD_SET(ConnectionNumber(dpy), &readset);
select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
timeoutOrInfty);
/* Check any expired timers */
checkTimerHandlers();
}
}
#endif
#if 1
/*
* Cant use this because XPending() will make W_WaitForEvent
* return even if the event in the queue is not what we want,
@@ -1063,7 +441,7 @@ WMMaskEvent(Display *dpy, long mask, XEvent *event)
{
while (!XCheckMaskEvent(dpy, mask, event)) {
/* Do idle stuff while there are no timer or X events */
while (checkIdleHandlers()) {
while (W_CheckIdleHandlers()) {
if (XCheckMaskEvent(dpy, mask, event))
return;
}
@@ -1072,10 +450,9 @@ WMMaskEvent(Display *dpy, long mask, XEvent *event)
W_WaitForEvent(dpy, mask);
/* Check any expired timers */
checkTimerHandlers();
W_CheckTimerHandlers();
}
}
#endif
Bool
WMScreenPending(WMScreen *scr)

View File

@@ -1,586 +1,42 @@
/*
* This event handling stuff was based on Tk.
* adapted from wevent.c
* Handle events for non-GUI based applications
*/
#include "WINGsP.h"
#include "../src/config.h"
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <X11/Xos.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include <time.h>
#ifndef X_GETTIMEOFDAY
#define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
#endif
typedef struct TimerHandler {
WMCallback *callback; /* procedure to call */
struct timeval when; /* when to call the callback */
void *clientData;
struct TimerHandler *next;
} TimerHandler;
typedef struct IdleHandler {
WMCallback *callback;
void *clientData;
} IdleHandler;
typedef struct InputHandler {
WMInputProc *callback;
void *clientData;
int fd;
int mask;
} InputHandler;
/* queue of timer event handlers */
static TimerHandler *timerHandler=NULL;
static WMBag *idleHandler=NULL;
static WMBag *inputHandler=NULL;
#define timerPending() (timerHandler)
static void
rightNow(struct timeval *tv) {
X_GETTIMEOFDAY(tv);
}
/* is t1 after t2 ? */
#define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
(((t1).tv_sec == (t2).tv_sec) \
&& ((t1).tv_usec > (t2).tv_usec)))
static void
addmillisecs(struct timeval *tv, int milliseconds)
{
tv->tv_usec += milliseconds*1000;
tv->tv_sec += tv->tv_usec/1000000;
tv->tv_usec = tv->tv_usec%1000000;
}
WMHandlerID
WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
{
TimerHandler *handler, *tmp;
handler = malloc(sizeof(TimerHandler));
if (!handler)
return NULL;
rightNow(&handler->when);
addmillisecs(&handler->when, milliseconds);
handler->callback = callback;
handler->clientData = cdata;
/* insert callback in queue, sorted by time left */
if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
/* first in the queue */
handler->next = timerHandler;
timerHandler = handler;
} else {
tmp = timerHandler;
while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
tmp = tmp->next;
}
handler->next = tmp->next;
tmp->next = handler;
}
return handler;
}
void
WMDeleteTimerWithClientData(void *cdata)
{
TimerHandler *handler, *tmp;
if (!cdata || !timerHandler)
return;
tmp = timerHandler;
if (tmp->clientData==cdata) {
timerHandler = tmp->next;
wfree(tmp);
} else {
while (tmp->next) {
if (tmp->next->clientData==cdata) {
handler = tmp->next;
tmp->next = handler->next;
wfree(handler);
break;
}
tmp = tmp->next;
}
}
}
void
WMDeleteTimerHandler(WMHandlerID handlerID)
{
TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
if (!handler || !timerHandler)
return;
tmp = timerHandler;
if (tmp==handler) {
timerHandler = handler->next;
wfree(handler);
} else {
while (tmp->next) {
if (tmp->next==handler) {
tmp->next=handler->next;
wfree(handler);
break;
}
tmp = tmp->next;
}
}
}
WMHandlerID
WMAddIdleHandler(WMCallback *callback, void *cdata)
{
IdleHandler *handler;
handler = malloc(sizeof(IdleHandler));
if (!handler)
return NULL;
handler->callback = callback;
handler->clientData = cdata;
/* add handler at end of queue */
if (!idleHandler) {
idleHandler = WMCreateBag(16);
}
WMPutInBag(idleHandler, handler);
return handler;
}
void
WMDeleteIdleHandler(WMHandlerID handlerID)
{
IdleHandler *handler = (IdleHandler*)handlerID;
int pos;
if (!handler || !idleHandler)
return;
pos = WMGetFirstInBag(idleHandler, handler);
if (pos >= 0) {
wfree(handler);
WMDeleteFromBag(idleHandler, pos);
}
}
WMHandlerID
WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
{
InputHandler *handler;
handler = wmalloc(sizeof(InputHandler));
handler->fd = fd;
handler->mask = condition;
handler->callback = proc;
handler->clientData = clientData;
if (!inputHandler)
inputHandler = WMCreateBag(16);
WMPutInBag(inputHandler, handler);
return handler;
}
void
WMDeleteInputHandler(WMHandlerID handlerID)
{
InputHandler *handler = (InputHandler*)handlerID;
int pos;
if (!handler || !inputHandler)
return;
pos = WMGetFirstInBag(inputHandler, handler);
if (pos >= 0) {
wfree(handler);
WMDeleteFromBag(inputHandler, pos);
}
}
static Bool
checkIdleHandlers()
{
IdleHandler *handler;
WMBag *handlerCopy;
int i, n;
if (!idleHandler || WMGetBagItemCount(idleHandler)==0) {
W_FlushIdleNotificationQueue();
/* make sure an observer in queue didn't added an idle handler */
return (idleHandler!=NULL && WMGetBagItemCount(idleHandler)>0);
}
n = WMGetBagItemCount(idleHandler);
handlerCopy = WMCreateBag(n);
for (i=0; i<n; i++)
WMPutInBag(handlerCopy, WMGetFromBag(idleHandler, i));
for (i=0; i<n; i++) {
handler = WMGetFromBag(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(idleHandler, handler)<0)
continue;
(*handler->callback)(handler->clientData);
WMDeleteIdleHandler(handler);
wfree(handler);
}
WMFreeBag(handlerCopy);
W_FlushIdleNotificationQueue();
/* this is not necesarrily False, because one handler can re-add itself */
return (WMGetBagItemCount(idleHandler)>0);
}
static void
checkTimerHandlers()
{
TimerHandler *handler;
struct timeval now;
if (!timerHandler) {
W_FlushASAPNotificationQueue();
return;
}
rightNow(&now);
while (timerHandler && IS_AFTER(now, timerHandler->when)) {
handler = timerHandler;
timerHandler = timerHandler->next;
handler->next = NULL;
(*handler->callback)(handler->clientData);
wfree(handler);
}
W_FlushASAPNotificationQueue();
}
static void
delayUntilNextTimerEvent(struct timeval *delay)
{
struct timeval now;
if (!timerHandler) {
/* The return value of this function is only valid if there _are_
* active timers. */
delay->tv_sec = 0;
delay->tv_usec = 0;
return;
}
rightNow(&now);
if (IS_AFTER(now, timerHandler->when)) {
delay->tv_sec = 0;
delay->tv_usec = 0;
} else {
delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
if (delay->tv_usec < 0) {
delay->tv_usec += 1000000;
delay->tv_sec--;
}
}
}
/*
* This functions will handle input events on all registered file descriptors.
* Input:
* - waitForInput - True if we want the function to wait until an event
* appears on a file descriptor we watch, False if we
* want the function to immediately return if there is
* no data available on the file descriptors we watch.
* Output:
* if waitForInput is False, the function will return False if there are no
* input handlers registered, or if there is no data
* available on the registered ones, and will return True
* if there is at least one input handler that has data
* available.
* if waitForInput is True, the function will return False if there are no
* input handlers registered, else it will block until an
* event appears on one of the file descriptors it watches
* and then it will return True.
*
* If the retured value is True, the input handlers for the corresponding file
* descriptors are also called.
*
*/
static Bool
handleInputEvents(Bool waitForInput)
{
#if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
struct pollfd *fds;
InputHandler *handler;
int count, timeout, nfds, i;
if (!inputHandler || (nfds=WMGetBagItemCount(inputHandler))==0) {
W_FlushASAPNotificationQueue();
return False;
}
fds = wmalloc(nfds * sizeof(struct pollfd));
for (i = 0; i<nfds; i++) {
handler = WMGetFromBag(inputHandler, i);
fds[i].fd = handler->fd;
fds[i].events = 0;
if (handler->mask & WIReadMask)
fds[i].events |= POLLIN;
if (handler->mask & WIWriteMask)
fds[i].events |= POLLOUT;
#if 0 /* FIXME */
if (handler->mask & WIExceptMask)
FD_SET(handler->fd, &eset);
#endif
}
/*
* If we don't wait for input, set timeout to return immediately,
* else setup the timeout to the estimated time until the
* next timer expires or if no timer is pending to infinite.
*/
if (!waitForInput) {
timeout = 0;
} else if (timerPending()) {
struct timeval tv;
delayUntilNextTimerEvent(&tv);
timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
} else {
timeout = -1;
}
count = poll(fds, nfds, timeout);
if (count > 0) {
WMBag *handlerCopy = WMCreateBag(nfds);
for (i=0; i<nfds, i++)
WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
for (i=0; i<nfds; i++) {
int mask;
handler = WMGetFromBag(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(inputHandler, handler)<0)
continue;
mask = 0;
if ((handler->mask & WIReadMask) &&
(fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
mask |= WIReadMask;
if ((handler->mask & WIWriteMask) &&
(fds[i].revents & (POLLOUT | POLLWRBAND)))
mask |= WIWriteMask;
if ((handler->mask & WIExceptMask) &&
(fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
mask |= WIExceptMask;
if (mask!=0 && handler->callback) {
(*handler->callback)(handler->fd, mask,
handler->clientData);
}
}
WMFreeBag(handlerCopy);
}
wfree(fds);
W_FlushASAPNotificationQueue();
return (count > 0);
#else /* not HAVE_POLL */
#ifdef HAVE_SELECT
struct timeval timeout;
struct timeval *timeoutPtr;
fd_set rset, wset, eset;
int maxfd, nfds, i;
int count;
InputHandler *handler;
if (!inputHandler || (nfds=WMGetBagItemCount(inputHandler))==0) {
W_FlushASAPNotificationQueue();
return False;
}
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
maxfd = 0;
for (i=0; i<nfds; i++) {
handler = WMGetFromBag(inputHandler, i);
if (handler->mask & WIReadMask)
FD_SET(handler->fd, &rset);
if (handler->mask & WIWriteMask)
FD_SET(handler->fd, &wset);
if (handler->mask & WIExceptMask)
FD_SET(handler->fd, &eset);
if (maxfd < handler->fd)
maxfd = handler->fd;
}
/*
* If we don't wait for input, set timeout to return immediately,
* else setup the timeout to the estimated time until the
* next timer expires or if no timer is pending to infinite.
*/
if (!waitForInput) {
timeout.tv_sec = 0;
timeout.tv_usec = 0;
timeoutPtr = &timeout;
} else if (timerPending()) {
delayUntilNextTimerEvent(&timeout);
timeoutPtr = &timeout;
} else {
timeoutPtr = (struct timeval*)0;
}
count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
if (count > 0) {
WMBag *handlerCopy = WMCreateBag(nfds);
for (i=0; i<nfds; i++)
WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
for (i=0; i<nfds; i++) {
int mask;
handler = WMGetFromBag(handlerCopy, i);
/* check if the handler still exist or was removed by a callback */
if (WMGetFirstInBag(inputHandler, handler)<0)
continue;
mask = 0;
if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
mask |= WIReadMask;
if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
mask |= WIWriteMask;
if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
mask |= WIExceptMask;
if (mask!=0 && handler->callback) {
(*handler->callback)(handler->fd, mask,
handler->clientData);
}
}
WMFreeBag(handlerCopy);
}
W_FlushASAPNotificationQueue();
return (count > 0);
#else /* not HAVE_SELECT, not HAVE_POLL */
Neither select nor poll. You lose.
#endif /* HAVE_SELECT */
#endif /* HAVE_POLL */
}
void
WHandleEvents()
{
/* Check any expired timers */
checkTimerHandlers();
W_CheckTimerHandlers();
/* We need to make sure that we have some input handler before calling
* checkIdleHandlers() in a while loop, because else the while loop
* W_CheckIdleHandlers() in a while loop, because else the while loop
* can run forever (if some idle handler reinitiates itself).
*/
if (inputHandler && WMGetBagItemCount(inputHandler)>0) {
if (W_HaveInputHandlers()) {
/* Do idle and timer stuff while there are no input events */
/* Check again if there are still input handlers, because some idle
* handler could have removed them */
while (checkIdleHandlers() && WMGetBagItemCount(inputHandler)>0 &&
!handleInputEvents(False)) {
while (W_CheckIdleHandlers() && W_HaveInputHandlers() &&
!W_HandleInputEvents(False, -1)) {
/* dispatch timer events */
checkTimerHandlers();
W_CheckTimerHandlers();
}
} else {
checkIdleHandlers();
W_CheckIdleHandlers();
/* dispatch timer events */
checkTimerHandlers();
W_CheckTimerHandlers();
}
handleInputEvents(True);
W_HandleInputEvents(True, -1);
/* Check any expired timers */
checkTimerHandlers();
W_CheckTimerHandlers();
}

View File

@@ -800,7 +800,7 @@ StartUp(Bool defaultScreenOnly)
wCursor[WCUR_SELECT] = XCreateFontCursor(dpy, XC_cross);
/* signal handler stuff that gets called when a signal is caught */
WMAddEternalTimerHandler(500, delayedAction, NULL);
WMAddPersistentTimerHandler(500, delayedAction, NULL);
/* emergency exit... */
sig_action.sa_handler = handleSig;