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 // this should go to wevent.c and wutil.c too
59 #define timerPending() (timerHandler)
64 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
= WMCreateBag(16);
254 WMPutInBag(idleHandler
, handler
);
261 WMDeleteIdleHandler(WMHandlerID handlerID
)
263 IdleHandler
*handler
= (IdleHandler
*)handlerID
;
266 if (!handler
|| !idleHandler
)
269 pos
= WMGetFirstInBag(idleHandler
, handler
);
270 if (pos
!= WBNotFound
) {
272 WMDeleteFromBag(idleHandler
, pos
);
279 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
281 InputHandler
*handler
;
283 handler
= wmalloc(sizeof(InputHandler
));
286 handler
->mask
= condition
;
287 handler
->callback
= proc
;
288 handler
->clientData
= clientData
;
291 inputHandler
= WMCreateBag(16);
292 WMPutInBag(inputHandler
, handler
);
300 WMDeleteInputHandler(WMHandlerID handlerID
)
302 InputHandler
*handler
= (InputHandler
*)handlerID
;
305 if (!handler
|| !inputHandler
)
308 pos
= WMGetFirstInBag(inputHandler
, handler
);
309 if (pos
!= WBNotFound
) {
311 WMDeleteFromBag(inputHandler
, pos
);
317 W_CheckIdleHandlers(void)
319 IdleHandler
*handler
;
323 if (!idleHandler
|| WMGetBagItemCount(idleHandler
)==0) {
324 W_FlushIdleNotificationQueue();
325 /* make sure an observer in queue didn't added an idle handler */
326 return (idleHandler
!=NULL
&& WMGetBagItemCount(idleHandler
)>0);
329 handlerCopy
= WMCreateBag(WMGetBagItemCount(idleHandler
));
330 WMAppendBag(handlerCopy
, idleHandler
);
332 for (handler
= WMBagFirst(handlerCopy
, &iter
);
334 handler
= WMBagNext(handlerCopy
, &iter
)) {
335 /* check if the handler still exist or was removed by a callback */
336 if (WMGetFirstInBag(idleHandler
, handler
) == WBNotFound
)
339 (*handler
->callback
)(handler
->clientData
);
340 WMDeleteIdleHandler(handler
);
343 WMFreeBag(handlerCopy
);
345 W_FlushIdleNotificationQueue();
347 /* this is not necesarrily False, because one handler can re-add itself */
348 return (WMGetBagItemCount(idleHandler
)>0);
354 W_CheckTimerHandlers(void)
356 TimerHandler
*handler
;
360 W_FlushASAPNotificationQueue();
366 handler
= timerHandler
;
367 while (handler
&& IS_AFTER(now
, handler
->when
)) {
368 if (!IS_ZERO(handler
->when
)) {
369 SET_ZERO(handler
->when
);
370 (*handler
->callback
)(handler
->clientData
);
372 handler
= handler
->next
;
375 while (timerHandler
&& IS_ZERO(timerHandler
->when
)) {
376 handler
= timerHandler
;
377 timerHandler
= timerHandler
->next
;
379 if (handler
->nextDelay
> 0) {
381 addmillisecs(&handler
->when
, handler
->nextDelay
);
382 enqueueTimerHandler(handler
);
388 W_FlushASAPNotificationQueue();
393 * This functions will handle input events on all registered file descriptors.
395 * - waitForInput - True if we want the function to wait until an event
396 * appears on a file descriptor we watch, False if we
397 * want the function to immediately return if there is
398 * no data available on the file descriptors we watch.
399 * - inputfd - Extra input file descriptor to watch for input.
400 * This is only used when called from wevent.c to watch
401 * on ConnectionNumber(dpy) to avoid blocking of X events
402 * if we wait for input from other file handlers.
404 * if waitForInput is False, the function will return False if there are no
405 * input handlers registered, or if there is no data
406 * available on the registered ones, and will return True
407 * if there is at least one input handler that has data
409 * if waitForInput is True, the function will return False if there are no
410 * input handlers registered, else it will block until an
411 * event appears on one of the file descriptors it watches
412 * and then it will return True.
414 * If the retured value is True, the input handlers for the corresponding file
415 * descriptors are also called.
417 * Parametersshould be passed like this:
419 * waitForInput - apropriate value passed by the function who called us
420 * inputfd = ConnectionNumber(dpy)
422 * waitForInput - apropriate value passed by the function who called us
427 W_HandleInputEvents(Bool waitForInput
, int inputfd
)
429 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
431 InputHandler
*handler
;
432 int count
, timeout
, nfds
, i
, extrafd
;
434 extrafd
= (inputfd
< 0) ? 0 : 1;
437 nfds
= WMGetBagItemCount(inputHandler
);
441 if (!extrafd
&& nfds
==0) {
442 W_FlushASAPNotificationQueue();
446 fds
= wmalloc((nfds
+extrafd
) * sizeof(struct pollfd
));
448 /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
449 fds
[nfds
].fd
= inputfd
;
450 fds
[nfds
].events
= POLLIN
;
453 for (i
= 0; i
<nfds
; i
++) {
454 handler
= WMGetFromBag(inputHandler
, i
);
455 fds
[i
].fd
= handler
->fd
;
457 if (handler
->mask
& WIReadMask
)
458 fds
[i
].events
|= POLLIN
;
460 if (handler
->mask
& WIWriteMask
)
461 fds
[i
].events
|= POLLOUT
;
464 if (handler
->mask
& WIExceptMask
)
465 FD_SET(handler
->fd
, &eset
);
470 * Setup the timeout to the estimated time until the
471 * next timer expires.
475 } else if (timerPending()) {
477 delayUntilNextTimerEvent(&tv
);
478 timeout
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
483 count
= poll(fds
, nfds
+extrafd
, timeout
);
485 if (count
>0 && nfds
>0) {
486 WMBag
*handlerCopy
= WMCreateBag(nfds
);
488 for (i
=0; i
<nfds
; i
++)
489 WMPutInBag(handlerCopy
, WMGetFromBag(inputHandler
, i
));
491 for (i
=0; i
<nfds
; i
++) {
494 handler
= WMGetFromBag(handlerCopy
, i
);
495 /* check if the handler still exist or was removed by a callback */
496 if (WMGetFirstInBag(inputHandler
, handler
) == WBNotFound
)
501 if ((handler
->mask
& WIReadMask
) &&
502 (fds
[i
].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
)))
505 if ((handler
->mask
& WIWriteMask
) &&
506 (fds
[i
].revents
& (POLLOUT
| POLLWRBAND
)))
509 if ((handler
->mask
& WIExceptMask
) &&
510 (fds
[i
].revents
& (POLLHUP
| POLLNVAL
| POLLERR
)))
511 mask
|= WIExceptMask
;
513 if (mask
!=0 && handler
->callback
) {
514 (*handler
->callback
)(handler
->fd
, mask
,
515 handler
->clientData
);
519 WMFreeBag(handlerCopy
);
522 /* --oldway-- retval = ((inputfd < 0) ? (count > 0) :
523 fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI));*/
527 W_FlushASAPNotificationQueue();
532 struct timeval timeout
;
533 struct timeval
*timeoutPtr
;
534 fd_set rset
, wset
, eset
;
537 InputHandler
*handler
;
540 nfds
= WMGetBagItemCount(inputHandler
);
544 if (inputfd
<0 && nfds
==0) {
545 W_FlushASAPNotificationQueue();
556 FD_SET(inputfd
, &rset
);
560 for (i
=0; i
<nfds
; i
++) {
561 handler
= WMGetFromBag(inputHandler
, i
);
562 if (handler
->mask
& WIReadMask
)
563 FD_SET(handler
->fd
, &rset
);
565 if (handler
->mask
& WIWriteMask
)
566 FD_SET(handler
->fd
, &wset
);
568 if (handler
->mask
& WIExceptMask
)
569 FD_SET(handler
->fd
, &eset
);
571 if (maxfd
< handler
->fd
)
576 * Setup the timeout to the estimated time until the
577 * next timer expires.
581 timeoutPtr
= &timeout
;
582 } else if (timerPending()) {
583 delayUntilNextTimerEvent(&timeout
);
584 timeoutPtr
= &timeout
;
586 timeoutPtr
= (struct timeval
*)0;
589 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
591 if (count
>0 && nfds
>0) {
592 WMBag
*handlerCopy
= WMCreateBag(nfds
);
594 for (i
=0; i
<nfds
; i
++)
595 WMPutInBag(handlerCopy
, WMGetFromBag(inputHandler
, i
));
597 for (i
=0; i
<nfds
; i
++) {
600 handler
= WMGetFromBag(handlerCopy
, i
);
601 /* check if the handler still exist or was removed by a callback */
602 if (WMGetFirstInBag(inputHandler
, handler
) == WBNotFound
)
607 if ((handler
->mask
& WIReadMask
) && FD_ISSET(handler
->fd
, &rset
))
610 if ((handler
->mask
& WIWriteMask
) && FD_ISSET(handler
->fd
, &wset
))
613 if ((handler
->mask
& WIExceptMask
) && FD_ISSET(handler
->fd
, &eset
))
614 mask
|= WIExceptMask
;
616 if (mask
!=0 && handler
->callback
) {
617 (*handler
->callback
)(handler
->fd
, mask
,
618 handler
->clientData
);
622 WMFreeBag(handlerCopy
);
625 W_FlushASAPNotificationQueue();
627 /* --oldway-- return ((inputfd < 0) ? (count > 0) : FD_ISSET(inputfd, &rset));*/
629 #else /* not HAVE_SELECT, not HAVE_POLL */
630 Neither select nor poll
. You lose
.
631 #endif /* HAVE_SELECT */
632 #endif /* HAVE_POLL */