- Now when Window Maker calls wmsetbg to set the background, it will pass the
[wmaker-crm.git] / WINGs / handlers.c
blobc81b2b6e5f70af5186e878984534a0739b9e781b
2 /*
3 * WINGs internal handlers: timer, idle and input handlers
4 */
6 #include "WINGsP.h"
8 #include "../src/config.h"
10 #include <sys/types.h>
11 #include <unistd.h>
13 #include <X11/Xos.h>
15 #ifdef HAVE_SYS_SELECT_H
16 # include <sys/select.h>
17 #endif
19 #include <time.h>
21 #ifndef X_GETTIMEOFDAY
22 #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
23 #endif
28 typedef struct TimerHandler {
29 WMCallback *callback; /* procedure to call */
30 struct timeval when; /* when to call the callback */
31 void *clientData;
32 struct TimerHandler *next;
33 int nextDelay; /* 0 if it's one-shot */
34 } TimerHandler;
37 typedef struct IdleHandler {
38 WMCallback *callback;
39 void *clientData;
40 } IdleHandler;
43 typedef struct InputHandler {
44 WMInputProc *callback;
45 void *clientData;
46 int fd;
47 int mask;
48 } InputHandler;
51 /* queue of timer event handlers */
52 static TimerHandler *timerHandler=NULL;
54 static WMBag *idleHandler=NULL;
56 static WMBag *inputHandler=NULL;
58 #define timerPending() (timerHandler)
62 static void
63 rightNow(struct timeval *tv) {
64 X_GETTIMEOFDAY(tv);
67 /* is t1 after t2 ? */
68 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
69 (((t1).tv_sec == (t2).tv_sec) \
70 && ((t1).tv_usec > (t2).tv_usec)))
72 #define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
74 #define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
76 static void
77 addmillisecs(struct timeval *tv, int milliseconds)
79 tv->tv_usec += milliseconds*1000;
81 tv->tv_sec += tv->tv_usec/1000000;
82 tv->tv_usec = tv->tv_usec%1000000;
86 static void
87 enqueueTimerHandler(TimerHandler *handler)
89 TimerHandler *tmp;
91 /* insert callback in queue, sorted by time left */
92 if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
93 /* first in the queue */
94 handler->next = timerHandler;
95 timerHandler = handler;
96 } else {
97 tmp = timerHandler;
98 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
99 tmp = tmp->next;
101 handler->next = tmp->next;
102 tmp->next = handler;
107 static void
108 delayUntilNextTimerEvent(struct timeval *delay)
110 struct timeval now;
111 TimerHandler *handler;
113 handler = timerHandler;
114 while (handler && IS_ZERO(handler->when)) handler = handler->next;
116 if (!handler) {
117 /* The return value of this function is only valid if there _are_
118 timers active. */
119 delay->tv_sec = 0;
120 delay->tv_usec = 0;
121 return;
124 rightNow(&now);
125 if (IS_AFTER(now, handler->when)) {
126 delay->tv_sec = 0;
127 delay->tv_usec = 0;
128 } else {
129 delay->tv_sec = handler->when.tv_sec - now.tv_sec;
130 delay->tv_usec = handler->when.tv_usec - now.tv_usec;
131 if (delay->tv_usec < 0) {
132 delay->tv_usec += 1000000;
133 delay->tv_sec--;
139 WMHandlerID
140 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
142 TimerHandler *handler;
144 handler = malloc(sizeof(TimerHandler));
145 if (!handler)
146 return NULL;
148 rightNow(&handler->when);
149 addmillisecs(&handler->when, milliseconds);
150 handler->callback = callback;
151 handler->clientData = cdata;
152 handler->nextDelay = 0;
154 enqueueTimerHandler(handler);
156 return handler;
160 WMHandlerID
161 WMAddPersistentTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
163 TimerHandler *handler = WMAddTimerHandler(milliseconds, callback, cdata);
165 if (handler != NULL)
166 handler->nextDelay = milliseconds;
168 return handler;
173 void
174 WMDeleteTimerWithClientData(void *cdata)
176 TimerHandler *handler, *tmp;
178 if (!cdata || !timerHandler)
179 return;
181 tmp = timerHandler;
182 if (tmp->clientData==cdata) {
183 tmp->nextDelay = 0;
184 if (!IS_ZERO(tmp->when)) {
185 timerHandler = tmp->next;
186 wfree(tmp);
188 } else {
189 while (tmp->next) {
190 if (tmp->next->clientData==cdata) {
191 handler = tmp->next;
192 handler->nextDelay = 0;
193 if (IS_ZERO(handler->when))
194 break;
195 tmp->next = handler->next;
196 wfree(handler);
197 break;
199 tmp = tmp->next;
206 void
207 WMDeleteTimerHandler(WMHandlerID handlerID)
209 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
211 if (!handler || !timerHandler)
212 return;
214 tmp = timerHandler;
216 handler->nextDelay = 0;
218 if (IS_ZERO(handler->when))
219 return;
221 if (tmp==handler) {
222 timerHandler = handler->next;
223 wfree(handler);
224 } else {
225 while (tmp->next) {
226 if (tmp->next==handler) {
227 tmp->next=handler->next;
228 wfree(handler);
229 break;
231 tmp = tmp->next;
238 WMHandlerID
239 WMAddIdleHandler(WMCallback *callback, void *cdata)
241 IdleHandler *handler;
243 handler = malloc(sizeof(IdleHandler));
244 if (!handler)
245 return NULL;
247 handler->callback = callback;
248 handler->clientData = cdata;
249 /* add handler at end of queue */
250 if (!idleHandler) {
251 idleHandler = WMCreateBag(16);
253 WMPutInBag(idleHandler, handler);
255 return handler;
259 void
260 WMDeleteIdleHandler(WMHandlerID handlerID)
262 IdleHandler *handler = (IdleHandler*)handlerID;
263 int pos;
265 if (!handler || !idleHandler)
266 return;
268 pos = WMGetFirstInBag(idleHandler, handler);
269 if (pos != WBNotFound) {
270 wfree(handler);
271 WMDeleteFromBag(idleHandler, pos);
277 WMHandlerID
278 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
280 InputHandler *handler;
282 handler = wmalloc(sizeof(InputHandler));
284 handler->fd = fd;
285 handler->mask = condition;
286 handler->callback = proc;
287 handler->clientData = clientData;
289 if (!inputHandler)
290 inputHandler = WMCreateBag(16);
291 WMPutInBag(inputHandler, handler);
293 return handler;
298 void
299 WMDeleteInputHandler(WMHandlerID handlerID)
301 InputHandler *handler = (InputHandler*)handlerID;
302 int pos;
304 if (!handler || !inputHandler)
305 return;
307 pos = WMGetFirstInBag(inputHandler, handler);
308 if (pos != WBNotFound) {
309 wfree(handler);
310 WMDeleteFromBag(inputHandler, pos);
315 Bool
316 W_CheckIdleHandlers(void)
318 IdleHandler *handler;
319 WMBag *handlerCopy;
320 WMBagIterator iter;
322 if (!idleHandler || WMGetBagItemCount(idleHandler)==0) {
323 W_FlushIdleNotificationQueue();
324 /* make sure an observer in queue didn't added an idle handler */
325 return (idleHandler!=NULL && WMGetBagItemCount(idleHandler)>0);
328 handlerCopy = WMCreateBag(WMGetBagItemCount(idleHandler));
329 WMAppendBag(handlerCopy, idleHandler);
331 for (handler = WMBagFirst(handlerCopy, &iter);
332 iter != NULL;
333 handler = WMBagNext(handlerCopy, &iter)) {
334 /* check if the handler still exist or was removed by a callback */
335 if (WMGetFirstInBag(idleHandler, handler) == WBNotFound)
336 continue;
338 (*handler->callback)(handler->clientData);
339 WMDeleteIdleHandler(handler);
342 WMFreeBag(handlerCopy);
344 W_FlushIdleNotificationQueue();
346 /* this is not necesarrily False, because one handler can re-add itself */
347 return (WMGetBagItemCount(idleHandler)>0);
352 void
353 W_CheckTimerHandlers(void)
355 TimerHandler *handler;
356 struct timeval now;
358 if (!timerHandler) {
359 W_FlushASAPNotificationQueue();
360 return;
363 rightNow(&now);
365 handler = timerHandler;
366 while (handler && IS_AFTER(now, handler->when)) {
367 if (!IS_ZERO(handler->when)) {
368 SET_ZERO(handler->when);
369 (*handler->callback)(handler->clientData);
371 handler = handler->next;
374 while (timerHandler && IS_ZERO(timerHandler->when)) {
375 handler = timerHandler;
376 timerHandler = timerHandler->next;
378 if (handler->nextDelay > 0) {
379 handler->when = now;
380 addmillisecs(&handler->when, handler->nextDelay);
381 enqueueTimerHandler(handler);
382 } else {
383 wfree(handler);
387 W_FlushASAPNotificationQueue();
392 * This functions will handle input events on all registered file descriptors.
393 * Input:
394 * - waitForInput - True if we want the function to wait until an event
395 * appears on a file descriptor we watch, False if we
396 * want the function to immediately return if there is
397 * no data available on the file descriptors we watch.
398 * - inputfd - Extra input file descriptor to watch for input.
399 * This is only used when called from wevent.c to watch
400 * on ConnectionNumber(dpy) to avoid blocking of X events
401 * if we wait for input from other file handlers.
402 * Output:
403 * if waitForInput is False, the function will return False if there are no
404 * input handlers registered, or if there is no data
405 * available on the registered ones, and will return True
406 * if there is at least one input handler that has data
407 * available.
408 * if waitForInput is True, the function will return False if there are no
409 * input handlers registered, else it will block until an
410 * event appears on one of the file descriptors it watches
411 * and then it will return True.
413 * If the retured value is True, the input handlers for the corresponding file
414 * descriptors are also called.
416 * Parametersshould be passed like this:
417 * - from wevent.c:
418 * waitForInput - apropriate value passed by the function who called us
419 * inputfd = ConnectionNumber(dpy)
420 * - from wutil.c:
421 * waitForInput - apropriate value passed by the function who called us
422 * inputfd = -1
425 Bool
426 W_HandleInputEvents(Bool waitForInput, int inputfd)
428 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
429 struct poll fd *fds;
430 InputHandler *handler;
431 int count, timeout, nfds, i, extrafd;
433 extrafd = (inputfd < 0) ? 0 : 1;
435 if (inputHandler)
436 nfds = WMGetBagItemCount(inputHandler);
437 else
438 nfds = 0;
440 if (!extrafd && nfds==0) {
441 W_FlushASAPNotificationQueue();
442 return False;
445 fds = wmalloc((nfds+extrafd) * sizeof(struct pollfd));
446 if (extrafd) {
447 /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
448 fds[nfds].fd = inputfd;
449 fds[nfds].events = POLLIN;
452 for (i = 0; i<nfds; i++) {
453 handler = WMGetFromBag(inputHandler, i);
454 fds[i].fd = handler->fd;
455 fds[i].events = 0;
456 if (handler->mask & WIReadMask)
457 fds[i].events |= POLLIN;
459 if (handler->mask & WIWriteMask)
460 fds[i].events |= POLLOUT;
462 #if 0 /* FIXME */
463 if (handler->mask & WIExceptMask)
464 FD_SET(handler->fd, &eset);
465 #endif
469 * Setup the timeout to the estimated time until the
470 * next timer expires.
472 if (!waitForInput) {
473 timeout = 0;
474 } else if (timerPending()) {
475 struct timeval tv;
476 delayUntilNextTimerEvent(&tv);
477 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
478 } else {
479 timeout = -1;
482 count = poll(fds, nfds+extrafd, timeout);
484 if (count>0 && nfds>0) {
485 WMBag *handlerCopy = WMCreateBag(nfds);
487 for (i=0; i<nfds; i++)
488 WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
490 for (i=0; i<nfds; i++) {
491 int mask;
493 handler = WMGetFromBag(handlerCopy, i);
494 /* check if the handler still exist or was removed by a callback */
495 if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
496 continue;
498 mask = 0;
500 if ((handler->mask & WIReadMask) &&
501 (fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
502 mask |= WIReadMask;
504 if ((handler->mask & WIWriteMask) &&
505 (fds[i].revents & (POLLOUT | POLLWRBAND)))
506 mask |= WIWriteMask;
508 if ((handler->mask & WIExceptMask) &&
509 (fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
510 mask |= WIExceptMask;
512 if (mask!=0 && handler->callback) {
513 (*handler->callback)(handler->fd, mask,
514 handler->clientData);
518 WMFreeBag(handlerCopy);
521 /* --oldway-- retval = ((inputfd < 0) ? (count > 0) :
522 fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI));*/
524 wfree(fds);
526 W_FlushASAPNotificationQueue();
528 return (count > 0);
529 #else
530 #ifdef HAVE_SELECT
531 struct timeval timeout;
532 struct timeval *timeoutPtr;
533 fd_set rset, wset, eset;
534 int maxfd, nfds, i;
535 int count;
536 InputHandler *handler;
538 if (inputHandler)
539 nfds = WMGetBagItemCount(inputHandler);
540 else
541 nfds = 0;
543 if (inputfd<0 && nfds==0) {
544 W_FlushASAPNotificationQueue();
545 return False;
548 FD_ZERO(&rset);
549 FD_ZERO(&wset);
550 FD_ZERO(&eset);
552 if (inputfd < 0) {
553 maxfd = 0;
554 } else {
555 FD_SET(inputfd, &rset);
556 maxfd = inputfd;
559 for (i=0; i<nfds; i++) {
560 handler = WMGetFromBag(inputHandler, i);
561 if (handler->mask & WIReadMask)
562 FD_SET(handler->fd, &rset);
564 if (handler->mask & WIWriteMask)
565 FD_SET(handler->fd, &wset);
567 if (handler->mask & WIExceptMask)
568 FD_SET(handler->fd, &eset);
570 if (maxfd < handler->fd)
571 maxfd = handler->fd;
575 * Setup the timeout to the estimated time until the
576 * next timer expires.
578 if (!waitForInput) {
579 SET_ZERO(timeout);
580 timeoutPtr = &timeout;
581 } else if (timerPending()) {
582 delayUntilNextTimerEvent(&timeout);
583 timeoutPtr = &timeout;
584 } else {
585 timeoutPtr = (struct timeval*)0;
588 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
590 if (count>0 && nfds>0) {
591 WMBag *handlerCopy = WMCreateBag(nfds);
593 for (i=0; i<nfds; i++)
594 WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
596 for (i=0; i<nfds; i++) {
597 int mask;
599 handler = WMGetFromBag(handlerCopy, i);
600 /* check if the handler still exist or was removed by a callback */
601 if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
602 continue;
604 mask = 0;
606 if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
607 mask |= WIReadMask;
609 if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
610 mask |= WIWriteMask;
612 if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
613 mask |= WIExceptMask;
615 if (mask!=0 && handler->callback) {
616 (*handler->callback)(handler->fd, mask,
617 handler->clientData);
621 WMFreeBag(handlerCopy);
624 W_FlushASAPNotificationQueue();
626 /* --oldway-- return ((inputfd < 0) ? (count > 0) : FD_ISSET(inputfd, &rset));*/
627 return (count > 0);
628 #else /* not HAVE_SELECT, not HAVE_POLL */
629 Neither select nor poll. You lose.
630 #endif /* HAVE_SELECT */
631 #endif /* HAVE_POLL */