mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-18 20:10:29 +01:00
for arq in `git ls-files *.c`; do
echo $arq;
indent -linux -l115 $arq;
done
The different line break at 115 columns is because
I use a widescreen monitor :-)
567 lines
13 KiB
C
567 lines
13 KiB
C
|
|
/*
|
|
* WINGs internal handlers: timer, idle and input handlers
|
|
*/
|
|
|
|
#include "wconfig.h"
|
|
#include "WINGsP.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 WMArray *idleHandler = NULL;
|
|
|
|
static WMArray *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)))
|
|
|
|
#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 = WMCreateArrayWithDestructor(16, wfree);
|
|
}
|
|
WMAddToArray(idleHandler, handler);
|
|
|
|
return handler;
|
|
}
|
|
|
|
void WMDeleteIdleHandler(WMHandlerID handlerID)
|
|
{
|
|
IdleHandler *handler = (IdleHandler *) handlerID;
|
|
|
|
if (!handler || !idleHandler)
|
|
return;
|
|
|
|
WMRemoveFromArray(idleHandler, handler);
|
|
}
|
|
|
|
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 = WMCreateArrayWithDestructor(16, wfree);
|
|
WMAddToArray(inputHandler, handler);
|
|
|
|
return handler;
|
|
}
|
|
|
|
void WMDeleteInputHandler(WMHandlerID handlerID)
|
|
{
|
|
InputHandler *handler = (InputHandler *) handlerID;
|
|
|
|
if (!handler || !inputHandler)
|
|
return;
|
|
|
|
WMRemoveFromArray(inputHandler, handler);
|
|
}
|
|
|
|
Bool W_CheckIdleHandlers(void)
|
|
{
|
|
IdleHandler *handler;
|
|
WMArray *handlerCopy;
|
|
WMArrayIterator iter;
|
|
|
|
if (!idleHandler || WMGetArrayItemCount(idleHandler) == 0) {
|
|
W_FlushIdleNotificationQueue();
|
|
/* make sure an observer in queue didn't added an idle handler */
|
|
return (idleHandler != NULL && WMGetArrayItemCount(idleHandler) > 0);
|
|
}
|
|
|
|
handlerCopy = WMDuplicateArray(idleHandler);
|
|
|
|
WM_ITERATE_ARRAY(handlerCopy, handler, iter) {
|
|
/* check if the handler still exist or was removed by a callback */
|
|
if (WMGetFirstInArray(idleHandler, handler) == WANotFound)
|
|
continue;
|
|
|
|
(*handler->callback) (handler->clientData);
|
|
WMDeleteIdleHandler(handler);
|
|
}
|
|
|
|
WMFreeArray(handlerCopy);
|
|
|
|
W_FlushIdleNotificationQueue();
|
|
|
|
/* this is not necesarrily False, because one handler can re-add itself */
|
|
return (WMGetArrayItemCount(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();
|
|
}
|
|
|
|
/*
|
|
* 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 - apropriate value passed by the function who called us
|
|
* inputfd = ConnectionNumber(dpy)
|
|
* - from wutil.c:
|
|
* waitForInput - apropriate value passed by the function who called us
|
|
* 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;
|
|
|
|
extrafd = (inputfd < 0) ? 0 : 1;
|
|
|
|
if (inputHandler)
|
|
nfds = WMGetArrayItemCount(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;
|
|
}
|
|
|
|
/* use WM_ITERATE_ARRAY() here */
|
|
for (i = 0; i < nfds; i++) {
|
|
handler = WMGetFromArray(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) {
|
|
WMArray *handlerCopy = WMDuplicateArray(inputHandler);
|
|
int mask;
|
|
|
|
/* use WM_ITERATE_ARRAY() here */
|
|
for (i = 0; i < nfds; i++) {
|
|
handler = WMGetFromArray(handlerCopy, i);
|
|
/* check if the handler still exist or was removed by a callback */
|
|
if (WMGetFirstInArray(inputHandler, handler) == WANotFound)
|
|
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);
|
|
}
|
|
}
|
|
|
|
WMFreeArray(handlerCopy);
|
|
}
|
|
|
|
wfree(fds);
|
|
|
|
W_FlushASAPNotificationQueue();
|
|
|
|
return (count > 0);
|
|
#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 = WMGetArrayItemCount(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;
|
|
}
|
|
|
|
/* use WM_ITERATE_ARRAY() here */
|
|
for (i = 0; i < nfds; i++) {
|
|
handler = WMGetFromArray(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) {
|
|
WMArray *handlerCopy = WMDuplicateArray(inputHandler);
|
|
int mask;
|
|
|
|
/* use WM_ITERATE_ARRAY() here */
|
|
for (i = 0; i < nfds; i++) {
|
|
handler = WMGetFromArray(handlerCopy, i);
|
|
/* check if the handler still exist or was removed by a callback */
|
|
if (WMGetFirstInArray(inputHandler, handler) == WANotFound)
|
|
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);
|
|
}
|
|
}
|
|
|
|
WMFreeArray(handlerCopy);
|
|
}
|
|
|
|
W_FlushASAPNotificationQueue();
|
|
|
|
return (count > 0);
|
|
#else /* not HAVE_SELECT, not HAVE_POLL */
|
|
# error Neither select nor poll. You lose.
|
|
#endif /* HAVE_SELECT */
|
|
#endif /* HAVE_POLL */
|
|
}
|