4 * This event handling stuff was based on Tk.
9 #include "../src/config.h"
11 #include <sys/types.h>
19 //#include <X11/Xos.h>
21 #ifdef HAVE_SYS_SELECT_H
22 # include <sys/select.h>
27 #ifndef X_GETTIMEOFDAY
28 #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
34 typedef struct TimerHandler
{
35 WMCallback
*callback
; /* procedure to call */
36 struct timeval when
; /* when to call the callback */
38 struct TimerHandler
*next
;
42 typedef struct IdleHandler
{
45 struct IdleHandler
*next
;
49 typedef struct InputHandler
{
50 WMInputProc
*callback
;
54 struct InputHandler
*next
;
58 /* queue of timer event handlers */
59 static TimerHandler
*timerHandler
=NULL
;
61 static IdleHandler
*idleHandler
=NULL
;
63 static InputHandler
*inputHandler
=NULL
;
67 #define timerPending() (timerHandler)
69 #define idlePending() (idleHandler)
73 rightNow(struct timeval
*tv
) {
77 /* is t1 after t2 ? */
78 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
79 (((t1).tv_sec == (t2).tv_sec) \
80 && ((t1).tv_usec > (t2).tv_usec)))
84 addmillisecs(struct timeval
*tv
, int milliseconds
)
86 tv
->tv_usec
+= milliseconds
*1000;
88 tv
->tv_sec
+= tv
->tv_usec
/1000000;
89 tv
->tv_usec
= tv
->tv_usec
%1000000;
94 WMAddTimerHandler(int milliseconds
, WMCallback
*callback
, void *cdata
)
96 TimerHandler
*handler
, *tmp
;
98 handler
= malloc(sizeof(TimerHandler
));
102 rightNow(&handler
->when
);
103 addmillisecs(&handler
->when
, milliseconds
);
104 handler
->callback
= callback
;
105 handler
->clientData
= cdata
;
106 /* insert callback in queue, sorted by time left */
107 if (!timerHandler
|| !IS_AFTER(handler
->when
, timerHandler
->when
)) {
108 /* first in the queue */
109 handler
->next
= timerHandler
;
110 timerHandler
= handler
;
113 while (tmp
->next
&& IS_AFTER(handler
->when
, tmp
->next
->when
)) {
116 handler
->next
= tmp
->next
;
125 WMDeleteTimerWithClientData(void *cdata
)
127 TimerHandler
*handler
, *tmp
;
129 if (!cdata
|| !timerHandler
)
133 if (tmp
->clientData
==cdata
) {
134 timerHandler
= tmp
->next
;
138 if (tmp
->next
->clientData
==cdata
) {
140 tmp
->next
= handler
->next
;
152 WMDeleteTimerHandler(WMHandlerID handlerID
)
154 TimerHandler
*tmp
, *handler
=(TimerHandler
*)handlerID
;
156 if (!handler
|| !timerHandler
)
161 timerHandler
= handler
->next
;
165 if (tmp
->next
==handler
) {
166 tmp
->next
=handler
->next
;
178 WMAddIdleHandler(WMCallback
*callback
, void *cdata
)
180 IdleHandler
*handler
, *tmp
;
182 handler
= malloc(sizeof(IdleHandler
));
186 handler
->callback
= callback
;
187 handler
->clientData
= cdata
;
188 handler
->next
= NULL
;
189 /* add callback at end of queue */
191 idleHandler
= handler
;
206 WMDeleteIdleHandler(WMHandlerID handlerID
)
208 IdleHandler
*tmp
, *handler
= (IdleHandler
*)handlerID
;
210 if (!handler
|| !idleHandler
)
214 if (tmp
== handler
) {
215 idleHandler
= handler
->next
;
219 if (tmp
->next
== handler
) {
220 tmp
->next
= handler
->next
;
232 WMAddInputHandler(int fd
, int condition
, WMInputProc
*proc
, void *clientData
)
234 InputHandler
*handler
;
236 handler
= wmalloc(sizeof(InputHandler
));
239 handler
->mask
= condition
;
240 handler
->callback
= proc
;
241 handler
->clientData
= clientData
;
243 handler
->next
= inputHandler
;
245 inputHandler
= handler
;
252 WMDeleteInputHandler(WMHandlerID handlerID
)
254 InputHandler
*tmp
, *handler
= (InputHandler
*)handlerID
;
256 if (!handler
|| !inputHandler
)
260 if (tmp
== handler
) {
261 inputHandler
= handler
->next
;
265 if (tmp
->next
== handler
) {
266 tmp
->next
= handler
->next
;
279 IdleHandler
*handler
, *tmp
;
282 W_FlushIdleNotificationQueue();
286 handler
= idleHandler
;
288 /* we will process all idleHandlers so, empty the handler list */
293 (*handler
->callback
)(handler
->clientData
);
294 /* remove the handler */
299 W_FlushIdleNotificationQueue();
307 TimerHandler
*handler
;
312 while (timerHandler
&& IS_AFTER(now
, timerHandler
->when
)) {
313 handler
= timerHandler
;
314 timerHandler
= timerHandler
->next
;
315 handler
->next
= NULL
;
316 (*handler
->callback
)(handler
->clientData
);
320 W_FlushASAPNotificationQueue();
326 delayUntilNextTimerEvent(struct timeval
*delay
)
331 /* The return value of this function is only valid if there _are_
339 if (IS_AFTER(now
, timerHandler
->when
)) {
343 delay
->tv_sec
= timerHandler
->when
.tv_sec
- now
.tv_sec
;
344 delay
->tv_usec
= timerHandler
->when
.tv_usec
- now
.tv_usec
;
345 if (delay
->tv_usec
< 0) {
346 delay
->tv_usec
+= 1000000;
354 W_WaitForEvent(Display
*dpy
, unsigned long xeventmask
)
356 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
358 InputHandler
*handler
;
359 int count
, timeout
, nfds
, k
, retval
;
361 for (nfds
= 1, handler
= inputHandler
;
362 handler
!= 0; handler
= handler
->next
) nfds
++;
364 fds
= wmalloc(nfds
* sizeof(struct pollfd
));
365 fds
[0].fd
= ConnectionNumber(dpy
);
366 fds
[0].events
= POLLIN
;
368 for (k
= 1, handler
= inputHandler
;
370 handler
= handler
->next
, k
++) {
371 fds
[k
].fd
= handler
->fd
;
373 if (handler
->mask
& WIReadMask
)
374 fds
[k
].events
|= POLLIN
;
376 if (handler
->mask
& WIWriteMask
)
377 fds
[k
].events
|= POLLOUT
;
380 if (handler
->mask
& WIExceptMask
)
381 FD_SET(handler
->fd
, &eset
);
386 * Setup the select() timeout to the estimated time until the
387 * next timer expires.
389 if (timerPending()) {
391 delayUntilNextTimerEvent(&tv
);
392 timeout
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
402 if (XCheckMaskEvent(dpy
, xeventmask
, &ev
)) {
403 XPutBackEvent(dpy
, &ev
);
408 count
= poll(fds
, nfds
, timeout
);
411 handler
= inputHandler
;
419 if (fds
[k
].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
))
422 if (fds
[k
].revents
& (POLLOUT
| POLLWRBAND
))
425 if (fds
[k
].revents
& (POLLHUP
| POLLNVAL
| POLLERR
))
426 mask
|= WIExceptMask
;
428 next
= handler
->next
;
430 if (mask
!=0 && handler
->callback
) {
431 (*handler
->callback
)(handler
->fd
, mask
,
432 handler
->clientData
);
440 retval
= fds
[0].revents
& (POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
);
443 W_FlushASAPNotificationQueue();
446 #else /* not HAVE_POLL */
448 struct timeval timeout
;
449 struct timeval
*timeoutPtr
;
450 fd_set rset
, wset
, eset
;
453 InputHandler
*handler
= inputHandler
;
459 FD_SET(ConnectionNumber(dpy
), &rset
);
460 maxfd
= ConnectionNumber(dpy
);
463 if (handler
->mask
& WIReadMask
)
464 FD_SET(handler
->fd
, &rset
);
466 if (handler
->mask
& WIWriteMask
)
467 FD_SET(handler
->fd
, &wset
);
469 if (handler
->mask
& WIExceptMask
)
470 FD_SET(handler
->fd
, &eset
);
472 if (maxfd
< handler
->fd
)
475 handler
= handler
->next
;
480 * Setup the select() timeout to the estimated time until the
481 * next timer expires.
483 if (timerPending()) {
484 delayUntilNextTimerEvent(&timeout
);
485 timeoutPtr
= &timeout
;
487 timeoutPtr
= (struct timeval
*)0;
496 if (XCheckMaskEvent(dpy
, xeventmask
, &ev
)) {
497 XPutBackEvent(dpy
, &ev
);
502 count
= select(1 + maxfd
, &rset
, &wset
, &eset
, timeoutPtr
);
505 handler
= inputHandler
;
513 if (FD_ISSET(handler
->fd
, &rset
))
516 if (FD_ISSET(handler
->fd
, &wset
))
519 if (FD_ISSET(handler
->fd
, &eset
))
520 mask
|= WIExceptMask
;
522 next
= handler
->next
;
524 if (mask
!=0 && handler
->callback
) {
525 (*handler
->callback
)(handler
->fd
, mask
,
526 handler
->clientData
);
533 W_FlushASAPNotificationQueue();
535 return FD_ISSET(ConnectionNumber(dpy
), &rset
);
536 #else /* not HAVE_SELECT, not HAVE_POLL */
537 Neither select nor poll
. You lose
.
538 #endif /* HAVE_SELECT */
539 #endif /* HAVE_POLL */
544 WMNextEvent(Display
*dpy
, XEvent
*event
)
546 /* Check any expired timers */
547 if (timerPending()) {
548 checkTimerHandlers();
551 while (XPending(dpy
) == 0) {
553 /* Do idle and timer stuff while there are no timer or X events */
554 while (!XPending(dpy
) && idlePending()) {
557 /* dispatch timer events */
559 checkTimerHandlers();
563 * Make sure that new events did not arrive while we were doing
564 * timer/idle stuff. Or we might block forever waiting for
565 * an event that already arrived.
567 /* wait to something happen */
568 W_WaitForEvent(dpy
, 0);
570 /* Check any expired timers */
571 if (timerPending()) {
572 checkTimerHandlers();
576 XNextEvent(dpy
, event
);