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 */