Started to make modifications to support libWUtil
[wmaker-crm.git] / WINGs / wutil.c
blobe7d6f6644fa59836bd62229be294771412c84eb3
3 /*
4 * This event handling stuff was based on Tk.
5 */
7 #include "WINGsP.h"
9 #include "../src/config.h"
11 #include <sys/types.h>
12 #include <unistd.h>
14 #ifdef HAVE_POLL_H
15 #include <poll.h>
16 #endif
19 //#include <X11/Xos.h>
21 #ifdef HAVE_SYS_SELECT_H
22 # include <sys/select.h>
23 #endif
25 #include <time.h>
27 #ifndef X_GETTIMEOFDAY
28 #define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
29 #endif
34 typedef struct TimerHandler {
35 WMCallback *callback; /* procedure to call */
36 struct timeval when; /* when to call the callback */
37 void *clientData;
38 struct TimerHandler *next;
39 } TimerHandler;
42 typedef struct IdleHandler {
43 WMCallback *callback;
44 void *clientData;
45 struct IdleHandler *next;
46 } IdleHandler;
49 typedef struct InputHandler {
50 WMInputProc *callback;
51 void *clientData;
52 int fd;
53 int mask;
54 struct InputHandler *next;
55 } InputHandler;
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)
72 static void
73 rightNow(struct timeval *tv) {
74 X_GETTIMEOFDAY(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)))
83 static void
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;
93 WMHandlerID
94 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
96 TimerHandler *handler, *tmp;
98 handler = malloc(sizeof(TimerHandler));
99 if (!handler)
100 return NULL;
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;
111 } else {
112 tmp = timerHandler;
113 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
114 tmp = tmp->next;
116 handler->next = tmp->next;
117 tmp->next = handler;
119 return handler;
124 void
125 WMDeleteTimerWithClientData(void *cdata)
127 TimerHandler *handler, *tmp;
129 if (!cdata || !timerHandler)
130 return;
132 tmp = timerHandler;
133 if (tmp->clientData==cdata) {
134 timerHandler = tmp->next;
135 free(tmp);
136 } else {
137 while (tmp->next) {
138 if (tmp->next->clientData==cdata) {
139 handler = tmp->next;
140 tmp->next = handler->next;
141 free(handler);
142 break;
144 tmp = tmp->next;
151 void
152 WMDeleteTimerHandler(WMHandlerID handlerID)
154 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
156 if (!handler || !timerHandler)
157 return;
159 tmp = timerHandler;
160 if (tmp==handler) {
161 timerHandler = handler->next;
162 free(handler);
163 } else {
164 while (tmp->next) {
165 if (tmp->next==handler) {
166 tmp->next=handler->next;
167 free(handler);
168 break;
170 tmp = tmp->next;
177 WMHandlerID
178 WMAddIdleHandler(WMCallback *callback, void *cdata)
180 IdleHandler *handler, *tmp;
182 handler = malloc(sizeof(IdleHandler));
183 if (!handler)
184 return NULL;
186 handler->callback = callback;
187 handler->clientData = cdata;
188 handler->next = NULL;
189 /* add callback at end of queue */
190 if (!idleHandler) {
191 idleHandler = handler;
192 } else {
193 tmp = idleHandler;
194 while (tmp->next) {
195 tmp = tmp->next;
197 tmp->next = handler;
200 return handler;
205 void
206 WMDeleteIdleHandler(WMHandlerID handlerID)
208 IdleHandler *tmp, *handler = (IdleHandler*)handlerID;
210 if (!handler || !idleHandler)
211 return;
213 tmp = idleHandler;
214 if (tmp == handler) {
215 idleHandler = handler->next;
216 free(handler);
217 } else {
218 while (tmp->next) {
219 if (tmp->next == handler) {
220 tmp->next = handler->next;
221 free(handler);
222 break;
224 tmp = tmp->next;
231 WMHandlerID
232 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
234 InputHandler *handler;
236 handler = wmalloc(sizeof(InputHandler));
238 handler->fd = fd;
239 handler->mask = condition;
240 handler->callback = proc;
241 handler->clientData = clientData;
243 handler->next = inputHandler;
245 inputHandler = handler;
247 return handler;
251 void
252 WMDeleteInputHandler(WMHandlerID handlerID)
254 InputHandler *tmp, *handler = (InputHandler*)handlerID;
256 if (!handler || !inputHandler)
257 return;
259 tmp = inputHandler;
260 if (tmp == handler) {
261 inputHandler = handler->next;
262 free(handler);
263 } else {
264 while (tmp->next) {
265 if (tmp->next == handler) {
266 tmp->next = handler->next;
267 free(handler);
268 break;
270 tmp = tmp->next;
276 static void
277 checkIdleHandlers()
279 IdleHandler *handler, *tmp;
281 if (!idleHandler) {
282 W_FlushIdleNotificationQueue();
283 return;
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 free(handler);
297 handler = tmp;
299 W_FlushIdleNotificationQueue();
304 static void
305 checkTimerHandlers()
307 TimerHandler *handler;
308 struct timeval now;
310 rightNow(&now);
312 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
313 handler = timerHandler;
314 timerHandler = timerHandler->next;
315 handler->next = NULL;
316 (*handler->callback)(handler->clientData);
317 free(handler);
320 W_FlushASAPNotificationQueue();
325 static void
326 delayUntilNextTimerEvent(struct timeval *delay)
328 struct timeval now;
330 if (!timerHandler) {
331 /* The return value of this function is only valid if there _are_
332 timers active. */
333 delay->tv_sec = 0;
334 delay->tv_usec = 0;
335 return;
338 rightNow(&now);
339 if (IS_AFTER(now, timerHandler->when)) {
340 delay->tv_sec = 0;
341 delay->tv_usec = 0;
342 } else {
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;
347 delay->tv_sec--;
353 Bool
354 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
356 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
357 struct pollfd *fds;
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;
369 handler;
370 handler = handler->next, k++) {
371 fds[k].fd = handler->fd;
372 fds[k].events = 0;
373 if (handler->mask & WIReadMask)
374 fds[k].events |= POLLIN;
376 if (handler->mask & WIWriteMask)
377 fds[k].events |= POLLOUT;
379 #if 0 /* FIXME */
380 if (handler->mask & WIExceptMask)
381 FD_SET(handler->fd, &eset);
382 #endif
386 * Setup the select() timeout to the estimated time until the
387 * next timer expires.
389 if (timerPending()) {
390 struct timeval tv;
391 delayUntilNextTimerEvent(&tv);
392 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
393 } else {
394 timeout = -1;
397 if (xeventmask==0) {
398 if (XPending(dpy))
399 return True;
400 } else {
401 XEvent ev;
402 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
403 XPutBackEvent(dpy, &ev);
404 return True;
408 count = poll(fds, nfds, timeout);
410 if (count > 0) {
411 handler = inputHandler;
412 k = 1;
413 while (handler) {
414 int mask;
415 InputHandler *next;
417 mask = 0;
419 if (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI))
420 mask |= WIReadMask;
422 if (fds[k].revents & (POLLOUT | POLLWRBAND))
423 mask |= WIWriteMask;
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);
435 handler = next;
436 k++;
440 retval = fds[0].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
441 free(fds);
443 W_FlushASAPNotificationQueue();
445 return retval;
446 #else /* not HAVE_POLL */
447 #ifdef HAVE_SELECT
448 struct timeval timeout;
449 struct timeval *timeoutPtr;
450 fd_set rset, wset, eset;
451 int maxfd;
452 int count;
453 InputHandler *handler = inputHandler;
455 FD_ZERO(&rset);
456 FD_ZERO(&wset);
457 FD_ZERO(&eset);
459 FD_SET(ConnectionNumber(dpy), &rset);
460 maxfd = ConnectionNumber(dpy);
462 while (handler) {
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)
473 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;
486 } else {
487 timeoutPtr = (struct timeval*)0;
490 XSync(dpy, False);
491 if (xeventmask==0) {
492 if (XPending(dpy))
493 return True;
494 } else {
495 XEvent ev;
496 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
497 XPutBackEvent(dpy, &ev);
498 return True;
502 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
504 if (count > 0) {
505 handler = inputHandler;
507 while (handler) {
508 int mask;
509 InputHandler *next;
511 mask = 0;
513 if (FD_ISSET(handler->fd, &rset))
514 mask |= WIReadMask;
516 if (FD_ISSET(handler->fd, &wset))
517 mask |= WIWriteMask;
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);
529 handler = next;
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 */
543 void
544 WMNextEvent(Display *dpy, XEvent *event)
546 /* Check any expired timers */
547 if (timerPending()) {
548 checkTimerHandlers();
551 while (XPending(dpy) == 0) {
552 /* Do idle stuff */
553 /* Do idle and timer stuff while there are no timer or X events */
554 while (!XPending(dpy) && idlePending()) {
555 if (idlePending())
556 checkIdleHandlers();
557 /* dispatch timer events */
558 if (timerPending())
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);