fixed many bugs, removed linked list
[wmaker-crm.git] / WINGs / wutil.c
blob9286a2aee671450de15acb6c3fdcd231d8dd3664
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)
70 #define idlePending() (idleHandler)
73 static void
74 rightNow(struct timeval *tv) {
75 X_GETTIMEOFDAY(tv);
78 /* is t1 after t2 ? */
79 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
80 (((t1).tv_sec == (t2).tv_sec) \
81 && ((t1).tv_usec > (t2).tv_usec)))
84 static void
85 addmillisecs(struct timeval *tv, int milliseconds)
87 tv->tv_usec += milliseconds*1000;
89 tv->tv_sec += tv->tv_usec/1000000;
90 tv->tv_usec = tv->tv_usec%1000000;
94 WMHandlerID
95 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
97 TimerHandler *handler, *tmp;
99 handler = malloc(sizeof(TimerHandler));
100 if (!handler)
101 return NULL;
103 rightNow(&handler->when);
104 addmillisecs(&handler->when, milliseconds);
105 handler->callback = callback;
106 handler->clientData = cdata;
107 /* insert callback in queue, sorted by time left */
108 if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
109 /* first in the queue */
110 handler->next = timerHandler;
111 timerHandler = handler;
112 } else {
113 tmp = timerHandler;
114 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
115 tmp = tmp->next;
117 handler->next = tmp->next;
118 tmp->next = handler;
120 return handler;
125 void
126 WMDeleteTimerWithClientData(void *cdata)
128 TimerHandler *handler, *tmp;
130 if (!cdata || !timerHandler)
131 return;
133 tmp = timerHandler;
134 if (tmp->clientData==cdata) {
135 timerHandler = tmp->next;
136 free(tmp);
137 } else {
138 while (tmp->next) {
139 if (tmp->next->clientData==cdata) {
140 handler = tmp->next;
141 tmp->next = handler->next;
142 free(handler);
143 break;
145 tmp = tmp->next;
152 void
153 WMDeleteTimerHandler(WMHandlerID handlerID)
155 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
157 if (!handler || !timerHandler)
158 return;
160 tmp = timerHandler;
161 if (tmp==handler) {
162 timerHandler = handler->next;
163 free(handler);
164 } else {
165 while (tmp->next) {
166 if (tmp->next==handler) {
167 tmp->next=handler->next;
168 free(handler);
169 break;
171 tmp = tmp->next;
178 WMHandlerID
179 WMAddIdleHandler(WMCallback *callback, void *cdata)
181 IdleHandler *handler, *tmp;
183 handler = malloc(sizeof(IdleHandler));
184 if (!handler)
185 return NULL;
187 handler->callback = callback;
188 handler->clientData = cdata;
189 handler->next = NULL;
190 /* add callback at end of queue */
191 if (!idleHandler) {
192 idleHandler = handler;
193 } else {
194 tmp = idleHandler;
195 while (tmp->next) {
196 tmp = tmp->next;
198 tmp->next = handler;
201 return handler;
206 void
207 WMDeleteIdleHandler(WMHandlerID handlerID)
209 IdleHandler *tmp, *handler = (IdleHandler*)handlerID;
211 if (!handler || !idleHandler)
212 return;
214 tmp = idleHandler;
215 if (tmp == handler) {
216 idleHandler = handler->next;
217 free(handler);
218 } else {
219 while (tmp->next) {
220 if (tmp->next == handler) {
221 tmp->next = handler->next;
222 free(handler);
223 break;
225 tmp = tmp->next;
232 WMHandlerID
233 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
235 InputHandler *handler;
237 handler = wmalloc(sizeof(InputHandler));
239 handler->fd = fd;
240 handler->mask = condition;
241 handler->callback = proc;
242 handler->clientData = clientData;
244 handler->next = inputHandler;
246 inputHandler = handler;
248 return handler;
252 void
253 WMDeleteInputHandler(WMHandlerID handlerID)
255 InputHandler *tmp, *handler = (InputHandler*)handlerID;
257 if (!handler || !inputHandler)
258 return;
260 tmp = inputHandler;
261 if (tmp == handler) {
262 inputHandler = handler->next;
263 free(handler);
264 } else {
265 while (tmp->next) {
266 if (tmp->next == handler) {
267 tmp->next = handler->next;
268 free(handler);
269 break;
271 tmp = tmp->next;
277 static void
278 checkIdleHandlers()
280 IdleHandler *handler, *tmp;
282 if (!idleHandler) {
283 W_FlushIdleNotificationQueue();
284 return;
287 handler = idleHandler;
289 /* we will process all idleHandlers so, empty the handler list */
290 idleHandler = NULL;
292 while (handler) {
293 tmp = handler->next;
294 (*handler->callback)(handler->clientData);
295 /* remove the handler */
296 free(handler);
298 handler = tmp;
300 W_FlushIdleNotificationQueue();
305 static void
306 checkTimerHandlers()
308 TimerHandler *handler;
309 struct timeval now;
311 rightNow(&now);
313 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
314 handler = timerHandler;
315 timerHandler = timerHandler->next;
316 handler->next = NULL;
317 (*handler->callback)(handler->clientData);
318 free(handler);
321 W_FlushASAPNotificationQueue();
326 static void
327 delayUntilNextTimerEvent(struct timeval *delay)
329 struct timeval now;
331 if (!timerHandler) {
332 /* The return value of this function is only valid if there _are_
333 timers active. */
334 delay->tv_sec = 0;
335 delay->tv_usec = 0;
336 return;
339 rightNow(&now);
340 if (IS_AFTER(now, timerHandler->when)) {
341 delay->tv_sec = 0;
342 delay->tv_usec = 0;
343 } else {
344 delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
345 delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
346 if (delay->tv_usec < 0) {
347 delay->tv_usec += 1000000;
348 delay->tv_sec--;
355 * This functions will handle input events on all registered file descriptors.
356 * Input:
357 * - waitForInput - True if we want the function to wait until an event
358 * appears on a file descriptor we watch, False if we
359 * want the function to immediately return if there is
360 * no data available on the file descriptors we watch.
361 * Output:
362 * if waitForInput is False, the function will return False if there are no
363 * input handlers registered, or if there is no data
364 * available on the registered ones, and will return True
365 * if there is at least one input handler that has data
366 * available.
367 * if waitForInput is True, the function will return False if there are no
368 * input handlers registered, else it will block until an
369 * event appears on one of the file descriptors it watches
370 * and then it will return True.
372 * If the retured value is True, the input handlers for the corresponding file
373 * descriptors are also called.
376 static Bool
377 handleInputEvents(Bool waitForInput)
379 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
380 struct pollfd *fds;
381 InputHandler *handler;
382 int count, timeout, nfds, k;
384 if (!inputHandler)
385 return False;
387 for (nfds = 0, handler = inputHandler;
388 handler != 0; handler = handler->next) nfds++;
390 fds = wmalloc(nfds * sizeof(struct pollfd));
392 for (k = 0, handler = inputHandler;
393 handler;
394 handler = handler->next, k++) {
395 fds[k].fd = handler->fd;
396 fds[k].events = 0;
397 if (handler->mask & WIReadMask)
398 fds[k].events |= POLLIN;
400 if (handler->mask & WIWriteMask)
401 fds[k].events |= POLLOUT;
403 #if 0 /* FIXME */
404 if (handler->mask & WIExceptMask)
405 FD_SET(handler->fd, &eset);
406 #endif
410 * If we don't wait for input, set timeout to return immediately,
411 * else setup the timeout to the estimated time until the
412 * next timer expires or if no timer is pending to infinite.
414 if (!waitForInput) {
415 timeout = 0;
416 } else if (timerPending()) {
417 struct timeval tv;
418 delayUntilNextTimerEvent(&tv);
419 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
420 } else {
421 timeout = -1;
424 count = poll(fds, nfds, timeout);
426 if (count > 0) {
427 handler = inputHandler;
428 k = 0;
429 while (handler) {
430 int mask;
431 InputHandler *next;
433 mask = 0;
435 if (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI))
436 mask |= WIReadMask;
438 if (fds[k].revents & (POLLOUT | POLLWRBAND))
439 mask |= WIWriteMask;
441 if (fds[k].revents & (POLLHUP | POLLNVAL | POLLERR))
442 mask |= WIExceptMask;
444 next = handler->next;
446 if (mask!=0 && handler->callback) {
447 (*handler->callback)(handler->fd, mask,
448 handler->clientData);
451 handler = next;
452 k++;
456 free(fds);
458 W_FlushASAPNotificationQueue();
460 return (count > 0);
461 #else /* not HAVE_POLL */
462 #ifdef HAVE_SELECT
463 struct timeval timeout;
464 struct timeval *timeoutPtr;
465 fd_set rset, wset, eset;
466 int maxfd;
467 int count;
468 InputHandler *handler = inputHandler;
470 if (!inputHandler)
471 return False;
473 FD_ZERO(&rset);
474 FD_ZERO(&wset);
475 FD_ZERO(&eset);
477 maxfd = 0;
479 while (handler) {
480 if (handler->mask & WIReadMask)
481 FD_SET(handler->fd, &rset);
483 if (handler->mask & WIWriteMask)
484 FD_SET(handler->fd, &wset);
486 if (handler->mask & WIExceptMask)
487 FD_SET(handler->fd, &eset);
489 if (maxfd < handler->fd)
490 maxfd = handler->fd;
492 handler = handler->next;
496 * If we don't wait for input, set timeout to return immediately,
497 * else setup the timeout to the estimated time until the
498 * next timer expires or if no timer is pending to infinite.
500 if (!waitForInput) {
501 timeout.tv_sec = 0;
502 timeout.tv_usec = 0;
503 timeoutPtr = &timeout;
504 } else if (timerPending()) {
505 delayUntilNextTimerEvent(&timeout);
506 timeoutPtr = &timeout;
507 } else {
508 timeoutPtr = (struct timeval*)0;
511 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
513 if (count > 0) {
514 handler = inputHandler;
516 while (handler) {
517 int mask;
518 InputHandler *next;
520 mask = 0;
522 if (FD_ISSET(handler->fd, &rset))
523 mask |= WIReadMask;
525 if (FD_ISSET(handler->fd, &wset))
526 mask |= WIWriteMask;
528 if (FD_ISSET(handler->fd, &eset))
529 mask |= WIExceptMask;
531 next = handler->next;
533 if (mask!=0 && handler->callback) {
534 (*handler->callback)(handler->fd, mask,
535 handler->clientData);
538 handler = next;
542 W_FlushASAPNotificationQueue();
544 return (count > 0);
545 #else /* not HAVE_SELECT, not HAVE_POLL */
546 Neither select nor poll. You lose.
547 #endif /* HAVE_SELECT */
548 #endif /* HAVE_POLL */
552 void
553 WHandleEvents()
555 /* Check any expired timers */
556 if (timerPending()) {
557 checkTimerHandlers();
560 /* We need to make sure that we have some input handler before calling
561 * checkIdleHandlers() in a while loop, because else the while loop
562 * can run forever (if some idle handler reinitiates itself).
564 if (inputHandler) {
565 /* Do idle and timer stuff while there are no input events */
566 while (idlePending() && inputHandler && !handleInputEvents(False)) {
567 if (idlePending())
568 checkIdleHandlers();
569 /* dispatch timer events */
570 if (timerPending())
571 checkTimerHandlers();
573 } else {
574 if (idlePending())
575 checkIdleHandlers();
576 /* dispatch timer events */
577 if (timerPending())
578 checkTimerHandlers();
581 handleInputEvents(True);
583 /* Check any expired timers */
584 if (timerPending()) {
585 checkTimerHandlers();