diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index 1d27b548..9bb43ae4 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -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: ............................ diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 48a3c88b..fde1572f 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -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 \ diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h index e358292f..c9cb3231 100644 --- a/WINGs/WINGs/WINGs.h +++ b/WINGs/WINGs/WINGs.h @@ -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); diff --git a/WINGs/WINGs/WINGsP.h b/WINGs/WINGs/WINGsP.h index 8dde6f18..bb933a92 100644 --- a/WINGs/WINGs/WINGsP.h +++ b/WINGs/WINGs/WINGsP.h @@ -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 */ diff --git a/WINGs/handlers.c b/WINGs/handlers.c new file mode 100644 index 00000000..418fa188 --- /dev/null +++ b/WINGs/handlers.c @@ -0,0 +1,644 @@ + +/* + * WINGs internal handlers: timer, idle and input handlers + */ + +#include "WINGsP.h" + +#include "../src/config.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 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; 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) { + WMBag *handlerCopy = WMCreateBag(nfds); + + 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); + } + } + + 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; 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) { + WMBag *handlerCopy = WMCreateBag(nfds); + + 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); + } + } + + 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 */ +} + + diff --git a/WINGs/wevent.c b/WINGs/wevent.c index 4fb6aa02..2dfb1e38 100644 --- a/WINGs/wevent.c +++ b/WINGs/wevent.c @@ -6,55 +6,6 @@ #include "WINGsP.h" -#include "../src/config.h" - -#include -#include - -#ifdef HAVE_POLL_H -#include -#endif - - -#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; - /* 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; 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 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; 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); - } - } - - 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; 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 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; 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); - } - } - - 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) diff --git a/WINGs/wutil.c b/WINGs/wutil.c index fa7c7716..3ce410e9 100644 --- a/WINGs/wutil.c +++ b/WINGs/wutil.c @@ -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 -#include - -#ifdef HAVE_POLL_H -#include -#endif - - -#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; -} 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; icallback)(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; 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 - } - - /* - * 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; 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); - } - } - - 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; 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; - } - - /* - * 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; 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); - } - } - - 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(); } diff --git a/src/startup.c b/src/startup.c index bb779af2..00d3ce2b 100644 --- a/src/startup.c +++ b/src/startup.c @@ -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;