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 WMArray
*idleHandler
=NULL
;
56 static WMArray
*inputHandler
=NULL
;
58 #define timerPending() (timerHandler)
63 rightNow(struct timeval
*tv
)
68 /* is t1 after t2 ? */
69 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
70 (((t1).tv_sec == (t2).tv_sec) \
71 && ((t1).tv_usec > (t2).tv_usec)))
73 #define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
75 #define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
78 addmillisecs(struct timeval
*tv
, int milliseconds
)
80 tv
->tv_usec
+= milliseconds
*1000;
82 tv
->tv_sec
+= tv
->tv_usec
/1000000;
83 tv
->tv_usec
= tv
->tv_usec
%1000000;
88 enqueueTimerHandler(TimerHandler
*handler
)
92 /* insert callback in queue, sorted by time left */
93 if (!timerHandler
|| !IS_AFTER(handler
->when
, timerHandler
->when
)) {
94 /* first in the queue */
95 handler
->next
= timerHandler
;
96 timerHandler
= handler
;
99 while (tmp
->next
&& IS_AFTER(handler
->when
, tmp
->next
->when
)) {
102 handler
->next
= tmp
->next
;
109 delayUntilNextTimerEvent(struct timeval
*delay
)
112 TimerHandler
*handler
;
114 handler
= timerHandler
;
115 while (handler
&& IS_ZERO(handler
->when
)) handler
= handler
->next
;
118 /* The return value of this function is only valid if there _are_
126 if (IS_AFTER(now
, handler
->when
)) {
130 delay
->tv_sec
= handler
->when
.tv_sec
- now
.tv_sec
;
131 delay
->tv_usec
= handler
->when
.tv_usec
- now
.tv_usec
;
132 if (delay
->tv_usec
< 0) {
133 delay
->tv_usec
+= 1000000;
141 WMAddTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
143 TimerHandler
*handler
;
145 handler
= malloc(sizeof(TimerHandler
));
149 rightNow(&handler
->when
);
150 addmillisecs(&handler
->when
, milliseconds
);
151 handler
->callback
= callback
;
152 handler
->clientData
= cdata
;
153 handler
->nextDelay
= 0;
155 enqueueTimerHandler(handler
);
162 WMAddPersistentTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
164 TimerHandler
*handler
= WMAddTimerHandler(milliseconds
, callback
, cdata
);
167 handler
->nextDelay
= milliseconds
;
175 WMDeleteTimerWithClientData(void *cdata
)
177 TimerHandler
*handler
, *tmp
;
179 if (!cdata
|| !timerHandler
)
183 if (tmp
->clientData
==cdata
) {
185 if (!IS_ZERO(tmp
->when
)) {
186 timerHandler
= tmp
->next
;
191 if (tmp
->next
->clientData
==cdata
) {
193 handler
->nextDelay
= 0;
194 if (IS_ZERO(handler
->when
))
196 tmp
->next
= handler
->next
;
208 WMDeleteTimerHandler(WMHandlerID handlerID
)
210 TimerHandler
*tmp
, *handler
=(TimerHandler
*)handlerID
;
212 if (!handler
|| !timerHandler
)
217 handler
->nextDelay
= 0;
219 if (IS_ZERO(handler
->when
))
223 timerHandler
= handler
->next
;
227 if (tmp
->next
==handler
) {
228 tmp
->next
=handler
->next
;
240 WMAddIdleHandler(WMCallback
*callback
, void *cdata
)
242 IdleHandler
*handler
;
244 handler
= malloc(sizeof(IdleHandler
));
248 handler
->callback
= callback
;
249 handler
->clientData
= cdata
;
250 /* add handler at end of queue */
252 idleHandler
= WMCreateArrayWithDestructor(16, wfree
);
254 WMAddToArray(idleHandler
, handler
);
261 WMDeleteIdleHandler(WMHandlerID handlerID
)
263 IdleHandler
*handler
= (IdleHandler
*)handlerID
;
265 if (!handler
|| !idleHandler
)
268 WMRemoveFromArray(idleHandler
, handler
);
274 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
276 InputHandler
*handler
;
278 handler
= wmalloc(sizeof(InputHandler
));
281 handler
->mask
= condition
;
282 handler
->callback
= proc
;
283 handler
->clientData
= clientData
;
286 inputHandler
= WMCreateArrayWithDestructor(16, wfree
);
287 WMAddToArray(inputHandler
, handler
);
295 WMDeleteInputHandler(WMHandlerID handlerID
)
297 InputHandler
*handler
= (InputHandler
*)handlerID
;
299 if (!handler
|| !inputHandler
)
302 WMRemoveFromArray(inputHandler
, handler
);
307 W_CheckIdleHandlers(void)
309 IdleHandler
*handler
;
310 WMArray
*handlerCopy
;
311 WMArrayIterator iter
;
313 if (!idleHandler
|| WMGetArrayItemCount(idleHandler
)==0) {
314 W_FlushIdleNotificationQueue();
315 /* make sure an observer in queue didn't added an idle handler */
316 return (idleHandler
!=NULL
&& WMGetArrayItemCount(idleHandler
)>0);
319 handlerCopy
= WMDuplicateArray(idleHandler
);
321 WM_ITERATE_ARRAY(handlerCopy
, handler
, iter
) {
322 /* check if the handler still exist or was removed by a callback */
323 if (WMGetFirstInArray(idleHandler
, handler
) == WANotFound
)
326 (*handler
->callback
)(handler
->clientData
);
327 WMDeleteIdleHandler(handler
);
330 WMFreeArray(handlerCopy
);
332 W_FlushIdleNotificationQueue();
334 /* this is not necesarrily False, because one handler can re-add itself */
335 return (WMGetArrayItemCount(idleHandler
)>0);
341 W_CheckTimerHandlers(void)
343 TimerHandler
*handler
;
347 W_FlushASAPNotificationQueue();
353 handler
= timerHandler
;
354 while (handler
&& IS_AFTER(now
, handler
->when
)) {
355 if (!IS_ZERO(handler
->when
)) {
356 SET_ZERO(handler
->when
);
357 (*handler
->callback
)(handler
->clientData
);
359 handler
= handler
->next
;
362 while (timerHandler
&& IS_ZERO(timerHandler
->when
)) {
363 handler
= timerHandler
;
364 timerHandler
= timerHandler
->next
;
366 if (handler
->nextDelay
> 0) {
368 addmillisecs(&handler
->when
, handler
->nextDelay
);
369 enqueueTimerHandler(handler
);
375 W_FlushASAPNotificationQueue();
380 * This functions will handle input events on all registered file descriptors.
382 * - waitForInput - True if we want the function to wait until an event
383 * appears on a file descriptor we watch, False if we
384 * want the function to immediately return if there is
385 * no data available on the file descriptors we watch.
386 * - inputfd - Extra input file descriptor to watch for input.
387 * This is only used when called from wevent.c to watch
388 * on ConnectionNumber(dpy) to avoid blocking of X events
389 * if we wait for input from other file handlers.
391 * if waitForInput is False, the function will return False if there are no
392 * input handlers registered, or if there is no data
393 * available on the registered ones, and will return True
394 * if there is at least one input handler that has data
396 * if waitForInput is True, the function will return False if there are no
397 * input handlers registered, else it will block until an
398 * event appears on one of the file descriptors it watches
399 * and then it will return True.
401 * If the retured value is True, the input handlers for the corresponding file
402 * descriptors are also called.
404 * Parametersshould be passed like this:
406 * waitForInput - apropriate value passed by the function who called us
407 * inputfd = ConnectionNumber(dpy)
409 * waitForInput - apropriate value passed by the function who called us
414 W_HandleInputEvents(Bool waitForInput
, int inputfd
)
416 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
418 InputHandler
*handler
;
419 int count
, timeout
, nfds
, i
, extrafd
;
421 extrafd
= (inputfd
< 0) ? 0 : 1;
424 nfds
= WMGetArrayItemCount(inputHandler
);
428 if (!extrafd
&& nfds
==0) {
429 W_FlushASAPNotificationQueue();
433 fds
= wmalloc((nfds
+extrafd
) * sizeof(struct pollfd
));
435 /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
436 fds
[nfds
].fd
= inputfd
;
437 fds
[nfds
].events
= POLLIN
;
440 /* use WM_ITERATE_ARRAY() here */
441 for (i
= 0; i
<nfds
; i
++) {
442 handler
= WMGetFromArray(inputHandler
, i
);
443 fds
[i
].fd
= handler
->fd
;
445 if (handler
->mask
& WIReadMask
)
446 fds
[i
].events
|= POLLIN
;
448 if (handler
->mask
& WIWriteMask
)
449 fds
[i
].events
|= POLLOUT
;
452 if (handler
->mask
& WIExceptMask
)
453 FD_SET(handler
->fd
, &eset
);
458 * Setup the timeout to the estimated time until the
459 * next timer expires.
463 } else if (timerPending()) {
465 delayUntilNextTimerEvent(&tv
);
466 timeout
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
471 count
= poll(fds
, nfds
+extrafd
, timeout
);
473 if (count
>0 && nfds
>0) {
474 WMArray
*handlerCopy
= WMDuplicateArray(inputHandler
);
477 /* use WM_ITERATE_ARRAY() here */
478 for (i
=0; i
<nfds
; i
++) {
479 handler
= WMGetFromArray(handlerCopy
, i
);
480 /* check if the handler still exist or was removed by a callback */
481 if (WMGetFirstInArray(inputHandler
, handler
) == WANotFound
)
486 if ((handler
->mask
& WIReadMask
) &&
487 (fds
[i
].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
)))
490 if ((handler
->mask
& WIWriteMask
) &&
491 (fds
[i
].revents
& (POLLOUT
| POLLWRBAND
)))
494 if ((handler
->mask
& WIExceptMask
) &&
495 (fds
[i
].revents
& (POLLHUP
| POLLNVAL
| POLLERR
)))
496 mask
|= WIExceptMask
;
498 if (mask
!=0 && handler
->callback
) {
499 (*handler
->callback
)(handler
->fd
, mask
,
500 handler
->clientData
);
504 WMFreeArray(handlerCopy
);
509 W_FlushASAPNotificationQueue();
514 struct timeval timeout
;
515 struct timeval
*timeoutPtr
;
516 fd_set rset
, wset
, eset
;
519 InputHandler
*handler
;
522 nfds
= WMGetArrayItemCount(inputHandler
);
526 if (inputfd
<0 && nfds
==0) {
527 W_FlushASAPNotificationQueue();
538 FD_SET(inputfd
, &rset
);
542 /* use WM_ITERATE_ARRAY() here */
543 for (i
=0; i
<nfds
; i
++) {
544 handler
= WMGetFromArray(inputHandler
, i
);
545 if (handler
->mask
& WIReadMask
)
546 FD_SET(handler
->fd
, &rset
);
548 if (handler
->mask
& WIWriteMask
)
549 FD_SET(handler
->fd
, &wset
);
551 if (handler
->mask
& WIExceptMask
)
552 FD_SET(handler
->fd
, &eset
);
554 if (maxfd
< handler
->fd
)
559 * Setup the timeout to the estimated time until the
560 * next timer expires.
564 timeoutPtr
= &timeout
;
565 } else if (timerPending()) {
566 delayUntilNextTimerEvent(&timeout
);
567 timeoutPtr
= &timeout
;
569 timeoutPtr
= (struct timeval
*)0;
572 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
574 if (count
>0 && nfds
>0) {
575 WMArray
*handlerCopy
= WMDuplicateArray(inputHandler
);
578 /* use WM_ITERATE_ARRAY() here */
579 for (i
=0; i
<nfds
; i
++) {
580 handler
= WMGetFromArray(handlerCopy
, i
);
581 /* check if the handler still exist or was removed by a callback */
582 if (WMGetFirstInArray(inputHandler
, handler
) == WANotFound
)
587 if ((handler
->mask
& WIReadMask
) && FD_ISSET(handler
->fd
, &rset
))
590 if ((handler
->mask
& WIWriteMask
) && FD_ISSET(handler
->fd
, &wset
))
593 if ((handler
->mask
& WIExceptMask
) && FD_ISSET(handler
->fd
, &eset
))
594 mask
|= WIExceptMask
;
596 if (mask
!=0 && handler
->callback
) {
597 (*handler
->callback
)(handler
->fd
, mask
,
598 handler
->clientData
);
602 WMFreeArray(handlerCopy
);
605 W_FlushASAPNotificationQueue();
608 #else /* not HAVE_SELECT, not HAVE_POLL */
609 # error Neither select nor poll. You lose.
610 #endif /* HAVE_SELECT */
611 #endif /* HAVE_POLL */