4 * This event handling stuff was based on Tk.
5 * adapted from wevent.c
10 #include "../src/config.h"
12 #include <sys/types.h>
22 #ifdef HAVE_SYS_SELECT_H
23 # include <sys/select.h>
28 #ifndef X_GETTIMEOFDAY
29 #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
35 typedef struct TimerHandler
{
36 WMCallback
*callback
; /* procedure to call */
37 struct timeval when
; /* when to call the callback */
39 struct TimerHandler
*next
;
43 typedef struct IdleHandler
{
46 struct IdleHandler
*next
;
50 typedef struct InputHandler
{
51 WMInputProc
*callback
;
55 struct InputHandler
*next
;
59 /* queue of timer event handlers */
60 static TimerHandler
*timerHandler
=NULL
;
62 static IdleHandler
*idleHandler
=NULL
;
64 static InputHandler
*inputHandler
=NULL
;
68 #define timerPending() (timerHandler)
72 rightNow(struct timeval
*tv
) {
76 /* is t1 after t2 ? */
77 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
78 (((t1).tv_sec == (t2).tv_sec) \
79 && ((t1).tv_usec > (t2).tv_usec)))
83 addmillisecs(struct timeval
*tv
, int milliseconds
)
85 tv
->tv_usec
+= milliseconds
*1000;
87 tv
->tv_sec
+= tv
->tv_usec
/1000000;
88 tv
->tv_usec
= tv
->tv_usec
%1000000;
93 WMAddTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
95 TimerHandler
*handler
, *tmp
;
97 handler
= malloc(sizeof(TimerHandler
));
101 rightNow(&handler
->when
);
102 addmillisecs(&handler
->when
, milliseconds
);
103 handler
->callback
= callback
;
104 handler
->clientData
= cdata
;
105 /* insert callback in queue, sorted by time left */
106 if (!timerHandler
|| !IS_AFTER(handler
->when
, timerHandler
->when
)) {
107 /* first in the queue */
108 handler
->next
= timerHandler
;
109 timerHandler
= handler
;
112 while (tmp
->next
&& IS_AFTER(handler
->when
, tmp
->next
->when
)) {
115 handler
->next
= tmp
->next
;
124 WMDeleteTimerWithClientData(void *cdata
)
126 TimerHandler
*handler
, *tmp
;
128 if (!cdata
|| !timerHandler
)
132 if (tmp
->clientData
==cdata
) {
133 timerHandler
= tmp
->next
;
137 if (tmp
->next
->clientData
==cdata
) {
139 tmp
->next
= handler
->next
;
151 WMDeleteTimerHandler(WMHandlerID handlerID
)
153 TimerHandler
*tmp
, *handler
=(TimerHandler
*)handlerID
;
155 if (!handler
|| !timerHandler
)
160 timerHandler
= handler
->next
;
164 if (tmp
->next
==handler
) {
165 tmp
->next
=handler
->next
;
177 WMAddIdleHandler(WMCallback
*callback
, void *cdata
)
179 IdleHandler
*handler
, *tmp
;
181 handler
= malloc(sizeof(IdleHandler
));
185 handler
->callback
= callback
;
186 handler
->clientData
= cdata
;
187 handler
->next
= NULL
;
188 /* add callback at end of queue */
190 idleHandler
= handler
;
205 WMDeleteIdleHandler(WMHandlerID handlerID
)
207 IdleHandler
*tmp
, *handler
= (IdleHandler
*)handlerID
;
209 if (!handler
|| !idleHandler
)
213 if (tmp
== handler
) {
214 idleHandler
= handler
->next
;
218 if (tmp
->next
== handler
) {
219 tmp
->next
= handler
->next
;
231 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
233 InputHandler
*handler
;
235 handler
= wmalloc(sizeof(InputHandler
));
238 handler
->mask
= condition
;
239 handler
->callback
= proc
;
240 handler
->clientData
= clientData
;
242 handler
->next
= inputHandler
;
244 inputHandler
= handler
;
251 WMDeleteInputHandler(WMHandlerID handlerID
)
253 InputHandler
*tmp
, *handler
= (InputHandler
*)handlerID
;
255 if (!handler
|| !inputHandler
)
259 if (tmp
== handler
) {
260 inputHandler
= handler
->next
;
264 if (tmp
->next
== handler
) {
265 tmp
->next
= handler
->next
;
278 IdleHandler
*handler
, *tmp
;
281 W_FlushIdleNotificationQueue();
282 /* make sure an observer in queue didn't added an idle handler */
283 return (idleHandler
!=NULL
);
286 handler
= idleHandler
;
288 /* we will process all idleHandlers so, empty the handler list */
293 (*handler
->callback
)(handler
->clientData
);
294 /* remove the handler */
300 W_FlushIdleNotificationQueue();
302 /* this is not necesarrily False, because one handler can re-add itself */
303 return (idleHandler
!=NULL
);
311 TimerHandler
*handler
;
315 W_FlushASAPNotificationQueue();
321 while (timerHandler
&& IS_AFTER(now
, timerHandler
->when
)) {
322 handler
= timerHandler
;
323 timerHandler
= timerHandler
->next
;
324 handler
->next
= NULL
;
325 (*handler
->callback
)(handler
->clientData
);
329 W_FlushASAPNotificationQueue();
335 delayUntilNextTimerEvent(struct timeval
*delay
)
340 /* The return value of this function is only valid if there _are_
348 if (IS_AFTER(now
, timerHandler
->when
)) {
352 delay
->tv_sec
= timerHandler
->when
.tv_sec
- now
.tv_sec
;
353 delay
->tv_usec
= timerHandler
->when
.tv_usec
- now
.tv_usec
;
354 if (delay
->tv_usec
< 0) {
355 delay
->tv_usec
+= 1000000;
363 * This functions will handle input events on all registered file descriptors.
365 * - waitForInput - True if we want the function to wait until an event
366 * appears on a file descriptor we watch, False if we
367 * want the function to immediately return if there is
368 * no data available on the file descriptors we watch.
370 * if waitForInput is False, the function will return False if there are no
371 * input handlers registered, or if there is no data
372 * available on the registered ones, and will return True
373 * if there is at least one input handler that has data
375 * if waitForInput is True, the function will return False if there are no
376 * input handlers registered, else it will block until an
377 * event appears on one of the file descriptors it watches
378 * and then it will return True.
380 * If the retured value is True, the input handlers for the corresponding file
381 * descriptors are also called.
385 handleInputEvents(Bool waitForInput
)
387 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
389 InputHandler
*handler
;
390 int count
, timeout
, nfds
, k
;
393 W_FlushASAPNotificationQueue();
397 for (nfds
= 0, handler
= inputHandler
;
398 handler
!= 0; handler
= handler
->next
) nfds
++;
400 fds
= wmalloc(nfds
* sizeof(struct pollfd
));
402 for (k
= 0, handler
= inputHandler
;
404 handler
= handler
->next
, k
++) {
405 fds
[k
].fd
= handler
->fd
;
407 if (handler
->mask
& WIReadMask
)
408 fds
[k
].events
|= POLLIN
;
410 if (handler
->mask
& WIWriteMask
)
411 fds
[k
].events
|= POLLOUT
;
414 if (handler
->mask
& WIExceptMask
)
415 FD_SET(handler
->fd
, &eset
);
420 * If we don't wait for input, set timeout to return immediately,
421 * else setup the timeout to the estimated time until the
422 * next timer expires or if no timer is pending to infinite.
426 } else if (timerPending()) {
428 delayUntilNextTimerEvent(&tv
);
429 timeout
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
434 count
= poll(fds
, nfds
, timeout
);
437 handler
= inputHandler
;
445 if ((handler
->mask
& WIReadMask
) &&
446 (fds
[k
].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
)))
449 if ((handler
->mask
& WIWriteMask
) &&
450 (fds
[k
].revents
& (POLLOUT
| POLLWRBAND
)))
453 if ((handler
->mask
& WIExceptMask
) &&
454 (fds
[k
].revents
& (POLLHUP
| POLLNVAL
| POLLERR
)))
455 mask
|= WIExceptMask
;
457 next
= handler
->next
;
459 if (mask
!=0 && handler
->callback
) {
460 (*handler
->callback
)(handler
->fd
, mask
,
461 handler
->clientData
);
471 W_FlushASAPNotificationQueue();
474 #else /* not HAVE_POLL */
476 struct timeval timeout
;
477 struct timeval
*timeoutPtr
;
478 fd_set rset
, wset
, eset
;
481 InputHandler
*handler
= inputHandler
;
484 W_FlushASAPNotificationQueue();
495 if (handler
->mask
& WIReadMask
)
496 FD_SET(handler
->fd
, &rset
);
498 if (handler
->mask
& WIWriteMask
)
499 FD_SET(handler
->fd
, &wset
);
501 if (handler
->mask
& WIExceptMask
)
502 FD_SET(handler
->fd
, &eset
);
504 if (maxfd
< handler
->fd
)
507 handler
= handler
->next
;
511 * If we don't wait for input, set timeout to return immediately,
512 * else setup the timeout to the estimated time until the
513 * next timer expires or if no timer is pending to infinite.
518 timeoutPtr
= &timeout
;
519 } else if (timerPending()) {
520 delayUntilNextTimerEvent(&timeout
);
521 timeoutPtr
= &timeout
;
523 timeoutPtr
= (struct timeval
*)0;
526 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
529 handler
= inputHandler
;
537 if ((handler
->mask
& WIReadMask
) && FD_ISSET(handler
->fd
, &rset
))
540 if ((handler
->mask
& WIWriteMask
) && FD_ISSET(handler
->fd
, &wset
))
543 if ((handler
->mask
& WIExceptMask
) && FD_ISSET(handler
->fd
, &eset
))
544 mask
|= WIExceptMask
;
546 next
= handler
->next
;
548 if (mask
!=0 && handler
->callback
) {
549 (*handler
->callback
)(handler
->fd
, mask
,
550 handler
->clientData
);
557 W_FlushASAPNotificationQueue();
560 #else /* not HAVE_SELECT, not HAVE_POLL */
561 Neither select nor poll
. You lose
.
562 #endif /* HAVE_SELECT */
563 #endif /* HAVE_POLL */
570 /* Check any expired timers */
571 checkTimerHandlers();
573 /* We need to make sure that we have some input handler before calling
574 * checkIdleHandlers() in a while loop, because else the while loop
575 * can run forever (if some idle handler reinitiates itself).
578 /* Do idle and timer stuff while there are no input events */
579 /* We check InputHandler again because some idle handler could have
581 while (checkIdleHandlers() && inputHandler
&& !handleInputEvents(False
)) {
582 /* dispatch timer events */
583 checkTimerHandlers();
587 /* dispatch timer events */
588 checkTimerHandlers();
591 handleInputEvents(True
);
593 /* Check any expired timers */
594 checkTimerHandlers();