- Fixed problem calling W_FlushIdleNotificationQueue() when there was no idle
[wmaker-crm.git] / WINGs / wutil.c
blob3ab91e6072fb8f5cec0638fa0f2db99750a71a8d
3 /*
4 * This event handling stuff was based on Tk.
5 * adapted from wevent.c
6 */
8 #include "WINGsP.h"
10 #include "../src/config.h"
12 #include <sys/types.h>
13 #include <unistd.h>
15 #ifdef HAVE_POLL_H
16 #include <poll.h>
17 #endif
20 #include <X11/Xos.h>
22 #ifdef HAVE_SYS_SELECT_H
23 # include <sys/select.h>
24 #endif
26 #include <time.h>
28 #ifndef X_GETTIMEOFDAY
29 #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
30 #endif
35 typedef struct TimerHandler {
36 WMCallback *callback; /* procedure to call */
37 struct timeval when; /* when to call the callback */
38 void *clientData;
39 struct TimerHandler *next;
40 } TimerHandler;
43 typedef struct IdleHandler {
44 WMCallback *callback;
45 void *clientData;
46 struct IdleHandler *next;
47 } IdleHandler;
50 typedef struct InputHandler {
51 WMInputProc *callback;
52 void *clientData;
53 int fd;
54 int mask;
55 struct InputHandler *next;
56 } InputHandler;
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)
71 static void
72 rightNow(struct timeval *tv) {
73 X_GETTIMEOFDAY(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)))
82 static void
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;
92 WMHandlerID
93 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
95 TimerHandler *handler, *tmp;
97 handler = malloc(sizeof(TimerHandler));
98 if (!handler)
99 return NULL;
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;
110 } else {
111 tmp = timerHandler;
112 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
113 tmp = tmp->next;
115 handler->next = tmp->next;
116 tmp->next = handler;
118 return handler;
123 void
124 WMDeleteTimerWithClientData(void *cdata)
126 TimerHandler *handler, *tmp;
128 if (!cdata || !timerHandler)
129 return;
131 tmp = timerHandler;
132 if (tmp->clientData==cdata) {
133 timerHandler = tmp->next;
134 wfree(tmp);
135 } else {
136 while (tmp->next) {
137 if (tmp->next->clientData==cdata) {
138 handler = tmp->next;
139 tmp->next = handler->next;
140 wfree(handler);
141 break;
143 tmp = tmp->next;
150 void
151 WMDeleteTimerHandler(WMHandlerID handlerID)
153 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
155 if (!handler || !timerHandler)
156 return;
158 tmp = timerHandler;
159 if (tmp==handler) {
160 timerHandler = handler->next;
161 wfree(handler);
162 } else {
163 while (tmp->next) {
164 if (tmp->next==handler) {
165 tmp->next=handler->next;
166 wfree(handler);
167 break;
169 tmp = tmp->next;
176 WMHandlerID
177 WMAddIdleHandler(WMCallback *callback, void *cdata)
179 IdleHandler *handler, *tmp;
181 handler = malloc(sizeof(IdleHandler));
182 if (!handler)
183 return NULL;
185 handler->callback = callback;
186 handler->clientData = cdata;
187 handler->next = NULL;
188 /* add callback at end of queue */
189 if (!idleHandler) {
190 idleHandler = handler;
191 } else {
192 tmp = idleHandler;
193 while (tmp->next) {
194 tmp = tmp->next;
196 tmp->next = handler;
199 return handler;
204 void
205 WMDeleteIdleHandler(WMHandlerID handlerID)
207 IdleHandler *tmp, *handler = (IdleHandler*)handlerID;
209 if (!handler || !idleHandler)
210 return;
212 tmp = idleHandler;
213 if (tmp == handler) {
214 idleHandler = handler->next;
215 wfree(handler);
216 } else {
217 while (tmp->next) {
218 if (tmp->next == handler) {
219 tmp->next = handler->next;
220 wfree(handler);
221 break;
223 tmp = tmp->next;
230 WMHandlerID
231 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
233 InputHandler *handler;
235 handler = wmalloc(sizeof(InputHandler));
237 handler->fd = fd;
238 handler->mask = condition;
239 handler->callback = proc;
240 handler->clientData = clientData;
242 handler->next = inputHandler;
244 inputHandler = handler;
246 return handler;
250 void
251 WMDeleteInputHandler(WMHandlerID handlerID)
253 InputHandler *tmp, *handler = (InputHandler*)handlerID;
255 if (!handler || !inputHandler)
256 return;
258 tmp = inputHandler;
259 if (tmp == handler) {
260 inputHandler = handler->next;
261 wfree(handler);
262 } else {
263 while (tmp->next) {
264 if (tmp->next == handler) {
265 tmp->next = handler->next;
266 wfree(handler);
267 break;
269 tmp = tmp->next;
275 static Bool
276 checkIdleHandlers()
278 IdleHandler *handler, *tmp;
280 if (!idleHandler) {
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 */
289 idleHandler = NULL;
291 while (handler) {
292 tmp = handler->next;
293 (*handler->callback)(handler->clientData);
294 /* remove the handler */
295 wfree(handler);
297 handler = tmp;
300 W_FlushIdleNotificationQueue();
302 /* this is not necesarrily False, because one handler can re-add itself */
303 return (idleHandler!=NULL);
308 static void
309 checkTimerHandlers()
311 TimerHandler *handler;
312 struct timeval now;
314 rightNow(&now);
316 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
317 handler = timerHandler;
318 timerHandler = timerHandler->next;
319 handler->next = NULL;
320 (*handler->callback)(handler->clientData);
321 wfree(handler);
324 W_FlushASAPNotificationQueue();
329 static void
330 delayUntilNextTimerEvent(struct timeval *delay)
332 struct timeval now;
334 if (!timerHandler) {
335 /* The return value of this function is only valid if there _are_
336 timers active. */
337 delay->tv_sec = 0;
338 delay->tv_usec = 0;
339 return;
342 rightNow(&now);
343 if (IS_AFTER(now, timerHandler->when)) {
344 delay->tv_sec = 0;
345 delay->tv_usec = 0;
346 } else {
347 delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
348 delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
349 if (delay->tv_usec < 0) {
350 delay->tv_usec += 1000000;
351 delay->tv_sec--;
358 * This functions will handle input events on all registered file descriptors.
359 * Input:
360 * - waitForInput - True if we want the function to wait until an event
361 * appears on a file descriptor we watch, False if we
362 * want the function to immediately return if there is
363 * no data available on the file descriptors we watch.
364 * Output:
365 * if waitForInput is False, the function will return False if there are no
366 * input handlers registered, or if there is no data
367 * available on the registered ones, and will return True
368 * if there is at least one input handler that has data
369 * available.
370 * if waitForInput is True, the function will return False if there are no
371 * input handlers registered, else it will block until an
372 * event appears on one of the file descriptors it watches
373 * and then it will return True.
375 * If the retured value is True, the input handlers for the corresponding file
376 * descriptors are also called.
379 static Bool
380 handleInputEvents(Bool waitForInput)
382 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
383 struct pollfd *fds;
384 InputHandler *handler;
385 int count, timeout, nfds, k;
387 if (!inputHandler)
388 return False;
390 for (nfds = 0, handler = inputHandler;
391 handler != 0; handler = handler->next) nfds++;
393 fds = wmalloc(nfds * sizeof(struct pollfd));
395 for (k = 0, handler = inputHandler;
396 handler;
397 handler = handler->next, k++) {
398 fds[k].fd = handler->fd;
399 fds[k].events = 0;
400 if (handler->mask & WIReadMask)
401 fds[k].events |= POLLIN;
403 if (handler->mask & WIWriteMask)
404 fds[k].events |= POLLOUT;
406 #if 0 /* FIXME */
407 if (handler->mask & WIExceptMask)
408 FD_SET(handler->fd, &eset);
409 #endif
413 * If we don't wait for input, set timeout to return immediately,
414 * else setup the timeout to the estimated time until the
415 * next timer expires or if no timer is pending to infinite.
417 if (!waitForInput) {
418 timeout = 0;
419 } else if (timerPending()) {
420 struct timeval tv;
421 delayUntilNextTimerEvent(&tv);
422 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
423 } else {
424 timeout = -1;
427 count = poll(fds, nfds, timeout);
429 if (count > 0) {
430 handler = inputHandler;
431 k = 0;
432 while (handler) {
433 int mask;
434 InputHandler *next;
436 mask = 0;
438 if (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI))
439 mask |= WIReadMask;
441 if (fds[k].revents & (POLLOUT | POLLWRBAND))
442 mask |= WIWriteMask;
444 if (fds[k].revents & (POLLHUP | POLLNVAL | POLLERR))
445 mask |= WIExceptMask;
447 next = handler->next;
449 if (mask!=0 && handler->callback) {
450 (*handler->callback)(handler->fd, mask,
451 handler->clientData);
454 handler = next;
455 k++;
459 wfree(fds);
461 W_FlushASAPNotificationQueue();
463 return (count > 0);
464 #else /* not HAVE_POLL */
465 #ifdef HAVE_SELECT
466 struct timeval timeout;
467 struct timeval *timeoutPtr;
468 fd_set rset, wset, eset;
469 int maxfd;
470 int count;
471 InputHandler *handler = inputHandler;
473 if (!inputHandler)
474 return False;
476 FD_ZERO(&rset);
477 FD_ZERO(&wset);
478 FD_ZERO(&eset);
480 maxfd = 0;
482 while (handler) {
483 if (handler->mask & WIReadMask)
484 FD_SET(handler->fd, &rset);
486 if (handler->mask & WIWriteMask)
487 FD_SET(handler->fd, &wset);
489 if (handler->mask & WIExceptMask)
490 FD_SET(handler->fd, &eset);
492 if (maxfd < handler->fd)
493 maxfd = handler->fd;
495 handler = handler->next;
499 * If we don't wait for input, set timeout to return immediately,
500 * else setup the timeout to the estimated time until the
501 * next timer expires or if no timer is pending to infinite.
503 if (!waitForInput) {
504 timeout.tv_sec = 0;
505 timeout.tv_usec = 0;
506 timeoutPtr = &timeout;
507 } else if (timerPending()) {
508 delayUntilNextTimerEvent(&timeout);
509 timeoutPtr = &timeout;
510 } else {
511 timeoutPtr = (struct timeval*)0;
514 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
516 if (count > 0) {
517 handler = inputHandler;
519 while (handler) {
520 int mask;
521 InputHandler *next;
523 mask = 0;
525 if (FD_ISSET(handler->fd, &rset))
526 mask |= WIReadMask;
528 if (FD_ISSET(handler->fd, &wset))
529 mask |= WIWriteMask;
531 if (FD_ISSET(handler->fd, &eset))
532 mask |= WIExceptMask;
534 next = handler->next;
536 if (mask!=0 && handler->callback) {
537 (*handler->callback)(handler->fd, mask,
538 handler->clientData);
541 handler = next;
545 W_FlushASAPNotificationQueue();
547 return (count > 0);
548 #else /* not HAVE_SELECT, not HAVE_POLL */
549 Neither select nor poll. You lose.
550 #endif /* HAVE_SELECT */
551 #endif /* HAVE_POLL */
555 void
556 WHandleEvents()
558 /* Check any expired timers */
559 if (timerPending()) {
560 checkTimerHandlers();
563 /* We need to make sure that we have some input handler before calling
564 * checkIdleHandlers() in a while loop, because else the while loop
565 * can run forever (if some idle handler reinitiates itself).
567 if (inputHandler) {
568 /* Do idle and timer stuff while there are no input events */
569 while (checkIdleHandlers() && inputHandler && !handleInputEvents(False)) {
570 /* dispatch timer events */
571 if (timerPending())
572 checkTimerHandlers();
574 } else {
575 checkIdleHandlers();
576 /* dispatch timer events */
577 if (timerPending())
578 checkTimerHandlers();
581 handleInputEvents(True);
583 /* Check any expired timers */
584 if (timerPending()) {
585 checkTimerHandlers();