X-Git-Url: https://repo.or.cz/w/wmaker-crm.git/blobdiff_plain/59fc927dc9f183802621138534fa6eaafe5593ba..688a56e8ab67b56550e2874d9d7423f0d435bfd9:/WINGs/handlers.c diff --git a/WINGs/handlers.c b/WINGs/handlers.c dissimilarity index 80% index 84978f01..88682867 100644 --- a/WINGs/handlers.c +++ b/WINGs/handlers.c @@ -1,613 +1,566 @@ - -/* - * WINGs internal handlers: timer, idle and input handlers - */ - -#include "wconfig.h" -#include "WINGsP.h" - -#include -#include - -#include - -#ifdef HAVE_SYS_SELECT_H -# include -#endif - -#include - -#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; ifd; - 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; imask & 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; imask & 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; imask & 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 */ -} - - + +/* + * WINGs internal handlers: timer, idle and input handlers + */ + +#include "wconfig.h" +#include "WINGsP.h" + +#include +#include + +#include + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#include + +#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 */ +}