3 * WINGs internal handlers: timer, idle and input handlers
8 #include "../src/config.h"
10 #include <sys/types.h>
15 #ifdef HAVE_SYS_SELECT_H
16 # include <sys/select.h>
21 #ifndef X_GETTIMEOFDAY
22 #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
28 typedef struct TimerHandler
{
29 WMCallback
*callback
; /* procedure to call */
30 struct timeval when
; /* when to call the callback */
32 struct TimerHandler
*next
;
33 int nextDelay
; /* 0 if it's one-shot */
37 typedef struct IdleHandler
{
43 typedef struct InputHandler
{
44 WMInputProc
*callback
;
51 /* queue of timer event handlers */
52 static TimerHandler
*timerHandler
=NULL
;
54 static WMBag
*idleHandler
=NULL
;
56 static WMBag
*inputHandler
=NULL
;
58 #define timerPending() (timerHandler)
63 rightNow(struct timeval
*tv
) {
67 /* is t1 after t2 ? */
68 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
69 (((t1).tv_sec == (t2).tv_sec) \
70 && ((t1).tv_usec > (t2).tv_usec)))
72 #define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
74 #define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
77 addmillisecs(struct timeval
*tv
, int milliseconds
)
79 tv
->tv_usec
+= milliseconds
*1000;
81 tv
->tv_sec
+= tv
->tv_usec
/1000000;
82 tv
->tv_usec
= tv
->tv_usec
%1000000;
87 enqueueTimerHandler(TimerHandler
*handler
)
91 /* insert callback in queue, sorted by time left */
92 if (!timerHandler
|| !IS_AFTER(handler
->when
, timerHandler
->when
)) {
93 /* first in the queue */
94 handler
->next
= timerHandler
;
95 timerHandler
= handler
;
98 while (tmp
->next
&& IS_AFTER(handler
->when
, tmp
->next
->when
)) {
101 handler
->next
= tmp
->next
;
108 delayUntilNextTimerEvent(struct timeval
*delay
)
111 TimerHandler
*handler
;
113 handler
= timerHandler
;
114 while (handler
&& IS_ZERO(handler
->when
)) handler
= handler
->next
;
117 /* The return value of this function is only valid if there _are_
125 if (IS_AFTER(now
, handler
->when
)) {
129 delay
->tv_sec
= handler
->when
.tv_sec
- now
.tv_sec
;
130 delay
->tv_usec
= handler
->when
.tv_usec
- now
.tv_usec
;
131 if (delay
->tv_usec
< 0) {
132 delay
->tv_usec
+= 1000000;
140 WMAddTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
142 TimerHandler
*handler
;
144 handler
= malloc(sizeof(TimerHandler
));
148 rightNow(&handler
->when
);
149 addmillisecs(&handler
->when
, milliseconds
);
150 handler
->callback
= callback
;
151 handler
->clientData
= cdata
;
152 handler
->nextDelay
= 0;
154 enqueueTimerHandler(handler
);
161 WMAddPersistentTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
163 TimerHandler
*handler
= WMAddTimerHandler(milliseconds
, callback
, cdata
);
166 handler
->nextDelay
= milliseconds
;
174 WMDeleteTimerWithClientData(void *cdata
)
176 TimerHandler
*handler
, *tmp
;
178 if (!cdata
|| !timerHandler
)
182 if (tmp
->clientData
==cdata
) {
184 if (!IS_ZERO(tmp
->when
)) {
185 timerHandler
= tmp
->next
;
190 if (tmp
->next
->clientData
==cdata
) {
192 handler
->nextDelay
= 0;
193 if (IS_ZERO(handler
->when
))
195 tmp
->next
= handler
->next
;
207 WMDeleteTimerHandler(WMHandlerID handlerID
)
209 TimerHandler
*tmp
, *handler
=(TimerHandler
*)handlerID
;
211 if (!handler
|| !timerHandler
)
216 handler
->nextDelay
= 0;
218 if (IS_ZERO(handler
->when
))
222 timerHandler
= handler
->next
;
226 if (tmp
->next
==handler
) {
227 tmp
->next
=handler
->next
;
239 WMAddIdleHandler(WMCallback
*callback
, void *cdata
)
241 IdleHandler
*handler
;
243 handler
= malloc(sizeof(IdleHandler
));
247 handler
->callback
= callback
;
248 handler
->clientData
= cdata
;
249 /* add handler at end of queue */
251 idleHandler
= WMCreateBag(16);
253 WMPutInBag(idleHandler
, handler
);
260 WMDeleteIdleHandler(WMHandlerID handlerID
)
262 IdleHandler
*handler
= (IdleHandler
*)handlerID
;
265 if (!handler
|| !idleHandler
)
268 pos
= WMGetFirstInBag(idleHandler
, handler
);
269 if (pos
!= WBNotFound
) {
271 WMDeleteFromBag(idleHandler
, pos
);
278 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
280 InputHandler
*handler
;
282 handler
= wmalloc(sizeof(InputHandler
));
285 handler
->mask
= condition
;
286 handler
->callback
= proc
;
287 handler
->clientData
= clientData
;
290 inputHandler
= WMCreateBag(16);
291 WMPutInBag(inputHandler
, handler
);
299 WMDeleteInputHandler(WMHandlerID handlerID
)
301 InputHandler
*handler
= (InputHandler
*)handlerID
;
304 if (!handler
|| !inputHandler
)
307 pos
= WMGetFirstInBag(inputHandler
, handler
);
308 if (pos
!= WBNotFound
) {
310 WMDeleteFromBag(inputHandler
, pos
);
316 W_CheckIdleHandlers(void)
318 IdleHandler
*handler
;
322 if (!idleHandler
|| WMGetBagItemCount(idleHandler
)==0) {
323 W_FlushIdleNotificationQueue();
324 /* make sure an observer in queue didn't added an idle handler */
325 return (idleHandler
!=NULL
&& WMGetBagItemCount(idleHandler
)>0);
328 handlerCopy
= WMCreateBag(WMGetBagItemCount(idleHandler
));
329 WMAppendBag(handlerCopy
, idleHandler
);
331 for (handler
= WMBagFirst(handlerCopy
, &iter
);
333 handler
= WMBagNext(handlerCopy
, &iter
)) {
334 /* check if the handler still exist or was removed by a callback */
335 if (WMGetFirstInBag(idleHandler
, handler
) == WBNotFound
)
338 (*handler
->callback
)(handler
->clientData
);
339 WMDeleteIdleHandler(handler
);
342 WMFreeBag(handlerCopy
);
344 W_FlushIdleNotificationQueue();
346 /* this is not necesarrily False, because one handler can re-add itself */
347 return (WMGetBagItemCount(idleHandler
)>0);
353 W_CheckTimerHandlers(void)
355 TimerHandler
*handler
;
359 W_FlushASAPNotificationQueue();
365 handler
= timerHandler
;
366 while (handler
&& IS_AFTER(now
, handler
->when
)) {
367 if (!IS_ZERO(handler
->when
)) {
368 SET_ZERO(handler
->when
);
369 (*handler
->callback
)(handler
->clientData
);
371 handler
= handler
->next
;
374 while (timerHandler
&& IS_ZERO(timerHandler
->when
)) {
375 handler
= timerHandler
;
376 timerHandler
= timerHandler
->next
;
378 if (handler
->nextDelay
> 0) {
380 addmillisecs(&handler
->when
, handler
->nextDelay
);
381 enqueueTimerHandler(handler
);
387 W_FlushASAPNotificationQueue();
392 * This functions will handle input events on all registered file descriptors.
394 * - waitForInput - True if we want the function to wait until an event
395 * appears on a file descriptor we watch, False if we
396 * want the function to immediately return if there is
397 * no data available on the file descriptors we watch.
398 * - inputfd - Extra input file descriptor to watch for input.
399 * This is only used when called from wevent.c to watch
400 * on ConnectionNumber(dpy) to avoid blocking of X events
401 * if we wait for input from other file handlers.
403 * if waitForInput is False, the function will return False if there are no
404 * input handlers registered, or if there is no data
405 * available on the registered ones, and will return True
406 * if there is at least one input handler that has data
408 * if waitForInput is True, the function will return False if there are no
409 * input handlers registered, else it will block until an
410 * event appears on one of the file descriptors it watches
411 * and then it will return True.
413 * If the retured value is True, the input handlers for the corresponding file
414 * descriptors are also called.
416 * Parametersshould be passed like this:
418 * waitForInput - apropriate value passed by the function who called us
419 * inputfd = ConnectionNumber(dpy)
421 * waitForInput - apropriate value passed by the function who called us
426 W_HandleInputEvents(Bool waitForInput
, int inputfd
)
428 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
430 InputHandler
*handler
;
431 int count
, timeout
, nfds
, i
, extrafd
;
433 extrafd
= (inputfd
< 0) ? 0 : 1;
436 nfds
= WMGetBagItemCount(inputHandler
);
440 if (!extrafd
&& nfds
==0) {
441 W_FlushASAPNotificationQueue();
445 fds
= wmalloc((nfds
+extrafd
) * sizeof(struct pollfd
));
447 /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
448 fds
[nfds
].fd
= inputfd
;
449 fds
[nfds
].events
= POLLIN
;
452 for (i
= 0; i
<nfds
; i
++) {
453 handler
= WMGetFromBag(inputHandler
, i
);
454 fds
[i
].fd
= handler
->fd
;
456 if (handler
->mask
& WIReadMask
)
457 fds
[i
].events
|= POLLIN
;
459 if (handler
->mask
& WIWriteMask
)
460 fds
[i
].events
|= POLLOUT
;
463 if (handler
->mask
& WIExceptMask
)
464 FD_SET(handler
->fd
, &eset
);
469 * Setup the timeout to the estimated time until the
470 * next timer expires.
474 } else if (timerPending()) {
476 delayUntilNextTimerEvent(&tv
);
477 timeout
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
482 count
= poll(fds
, nfds
+extrafd
, timeout
);
484 if (count
>0 && nfds
>0) {
485 WMBag
*handlerCopy
= WMCreateBag(nfds
);
487 for (i
=0; i
<nfds
; i
++)
488 WMPutInBag(handlerCopy
, WMGetFromBag(inputHandler
, i
));
490 for (i
=0; i
<nfds
; i
++) {
493 handler
= WMGetFromBag(handlerCopy
, i
);
494 /* check if the handler still exist or was removed by a callback */
495 if (WMGetFirstInBag(inputHandler
, handler
) == WBNotFound
)
500 if ((handler
->mask
& WIReadMask
) &&
501 (fds
[i
].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
)))
504 if ((handler
->mask
& WIWriteMask
) &&
505 (fds
[i
].revents
& (POLLOUT
| POLLWRBAND
)))
508 if ((handler
->mask
& WIExceptMask
) &&
509 (fds
[i
].revents
& (POLLHUP
| POLLNVAL
| POLLERR
)))
510 mask
|= WIExceptMask
;
512 if (mask
!=0 && handler
->callback
) {
513 (*handler
->callback
)(handler
->fd
, mask
,
514 handler
->clientData
);
518 WMFreeBag(handlerCopy
);
521 /* --oldway-- retval = ((inputfd < 0) ? (count > 0) :
522 fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI));*/
526 W_FlushASAPNotificationQueue();
531 struct timeval timeout
;
532 struct timeval
*timeoutPtr
;
533 fd_set rset
, wset
, eset
;
536 InputHandler
*handler
;
539 nfds
= WMGetBagItemCount(inputHandler
);
543 if (inputfd
<0 && nfds
==0) {
544 W_FlushASAPNotificationQueue();
555 FD_SET(inputfd
, &rset
);
559 for (i
=0; i
<nfds
; i
++) {
560 handler
= WMGetFromBag(inputHandler
, i
);
561 if (handler
->mask
& WIReadMask
)
562 FD_SET(handler
->fd
, &rset
);
564 if (handler
->mask
& WIWriteMask
)
565 FD_SET(handler
->fd
, &wset
);
567 if (handler
->mask
& WIExceptMask
)
568 FD_SET(handler
->fd
, &eset
);
570 if (maxfd
< handler
->fd
)
575 * Setup the timeout to the estimated time until the
576 * next timer expires.
580 timeoutPtr
= &timeout
;
581 } else if (timerPending()) {
582 delayUntilNextTimerEvent(&timeout
);
583 timeoutPtr
= &timeout
;
585 timeoutPtr
= (struct timeval
*)0;
588 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
590 if (count
>0 && nfds
>0) {
591 WMBag
*handlerCopy
= WMCreateBag(nfds
);
593 for (i
=0; i
<nfds
; i
++)
594 WMPutInBag(handlerCopy
, WMGetFromBag(inputHandler
, i
));
596 for (i
=0; i
<nfds
; i
++) {
599 handler
= WMGetFromBag(handlerCopy
, i
);
600 /* check if the handler still exist or was removed by a callback */
601 if (WMGetFirstInBag(inputHandler
, handler
) == WBNotFound
)
606 if ((handler
->mask
& WIReadMask
) && FD_ISSET(handler
->fd
, &rset
))
609 if ((handler
->mask
& WIWriteMask
) && FD_ISSET(handler
->fd
, &wset
))
612 if ((handler
->mask
& WIExceptMask
) && FD_ISSET(handler
->fd
, &eset
))
613 mask
|= WIExceptMask
;
615 if (mask
!=0 && handler
->callback
) {
616 (*handler
->callback
)(handler
->fd
, mask
,
617 handler
->clientData
);
621 WMFreeBag(handlerCopy
);
624 W_FlushASAPNotificationQueue();
626 /* --oldway-- return ((inputfd < 0) ? (count > 0) : FD_ISSET(inputfd, &rset));*/
628 #else /* not HAVE_SELECT, not HAVE_POLL */
629 Neither select nor poll
. You lose
.
630 #endif /* HAVE_SELECT */
631 #endif /* HAVE_POLL */