fixed timerhandler cpu eater
[wmaker-crm.git] / WINGs / wevent.c
blob12e6e162769c0b4bde97e2687fb51e6d441a3a16
3 /*
4 * This event handling stuff was inspired 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
36 typedef struct TimerHandler {
37 WMCallback *callback; /* procedure to call */
38 struct timeval when; /* when to call the callback */
39 void *clientData;
40 struct TimerHandler *next;
41 int nextDelay; /* 0 if it's one-shot */
42 } TimerHandler;
45 typedef struct IdleHandler {
46 WMCallback *callback;
47 void *clientData;
48 } IdleHandler;
51 typedef struct InputHandler {
52 WMInputProc *callback;
53 void *clientData;
54 int fd;
55 int mask;
56 } InputHandler;
59 /* table to map event types to event masks */
60 static unsigned long eventMasks[] = {
63 KeyPressMask, /* KeyPress */
64 KeyReleaseMask, /* KeyRelease */
65 ButtonPressMask, /* ButtonPress */
66 ButtonReleaseMask, /* ButtonRelease */
67 PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
68 |Button1MotionMask|Button2MotionMask|Button3MotionMask
69 |Button4MotionMask|Button5MotionMask,
70 /* MotionNotify */
71 EnterWindowMask, /* EnterNotify */
72 LeaveWindowMask, /* LeaveNotify */
73 FocusChangeMask, /* FocusIn */
74 FocusChangeMask, /* FocusOut */
75 KeymapStateMask, /* KeymapNotify */
76 ExposureMask, /* Expose */
77 ExposureMask, /* GraphicsExpose */
78 ExposureMask, /* NoExpose */
79 VisibilityChangeMask, /* VisibilityNotify */
80 SubstructureNotifyMask, /* CreateNotify */
81 StructureNotifyMask, /* DestroyNotify */
82 StructureNotifyMask, /* UnmapNotify */
83 StructureNotifyMask, /* MapNotify */
84 SubstructureRedirectMask, /* MapRequest */
85 StructureNotifyMask, /* ReparentNotify */
86 StructureNotifyMask, /* ConfigureNotify */
87 SubstructureRedirectMask, /* ConfigureRequest */
88 StructureNotifyMask, /* GravityNotify */
89 ResizeRedirectMask, /* ResizeRequest */
90 StructureNotifyMask, /* CirculateNotify */
91 SubstructureRedirectMask, /* CirculateRequest */
92 PropertyChangeMask, /* PropertyNotify */
93 0, /* SelectionClear */
94 0, /* SelectionRequest */
95 0, /* SelectionNotify */
96 ColormapChangeMask, /* ColormapNotify */
97 ClientMessageMask, /* ClientMessage */
98 0, /* Mapping Notify */
103 /* queue of timer event handlers */
104 static TimerHandler *timerHandler=NULL;
106 static WMBag *idleHandler=NULL;
108 static WMBag *inputHandler=NULL;
110 /* hook for other toolkits or wmaker process their events */
111 static WMEventHook *extraEventHandler=NULL;
115 #define timerPending() (timerHandler)
119 static void
120 rightNow(struct timeval *tv) {
121 X_GETTIMEOFDAY(tv);
124 /* is t1 after t2 ? */
125 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
126 (((t1).tv_sec == (t2).tv_sec) \
127 && ((t1).tv_usec > (t2).tv_usec)))
129 #define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
131 #define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
133 static void
134 addmillisecs(struct timeval *tv, int milliseconds)
136 tv->tv_usec += milliseconds*1000;
138 tv->tv_sec += tv->tv_usec/1000000;
139 tv->tv_usec = tv->tv_usec%1000000;
143 static void
144 enqueueTimerHandler(TimerHandler *handler)
146 TimerHandler *tmp;
148 /* insert callback in queue, sorted by time left */
149 if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
150 /* first in the queue */
151 handler->next = timerHandler;
152 timerHandler = handler;
153 } else {
154 tmp = timerHandler;
155 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
156 tmp = tmp->next;
158 handler->next = tmp->next;
159 tmp->next = handler;
164 WMHandlerID
165 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
167 TimerHandler *handler;
169 handler = malloc(sizeof(TimerHandler));
170 if (!handler)
171 return NULL;
173 rightNow(&handler->when);
174 addmillisecs(&handler->when, milliseconds);
175 handler->callback = callback;
176 handler->clientData = cdata;
177 handler->nextDelay = 0;
179 enqueueTimerHandler(handler);
181 return handler;
185 WMHandlerID
186 WMAddEternalTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
188 TimerHandler *handler = WMAddTimerHandler(milliseconds, callback, cdata);
190 if (handler != NULL)
191 handler->nextDelay = milliseconds;
193 return handler;
198 void
199 WMDeleteTimerWithClientData(void *cdata)
201 TimerHandler *handler, *tmp;
203 if (!cdata || !timerHandler)
204 return;
206 tmp = timerHandler;
207 if (tmp->clientData==cdata) {
208 tmp->nextDelay = 0;
209 if (!IS_ZERO(tmp->when)) {
210 timerHandler = tmp->next;
211 wfree(tmp);
213 } else {
214 while (tmp->next) {
215 if (tmp->next->clientData==cdata) {
216 handler = tmp->next;
217 handler->nextDelay = 0;
218 if (IS_ZERO(handler->when))
219 break;
220 tmp->next = handler->next;
221 wfree(handler);
222 break;
224 tmp = tmp->next;
231 void
232 WMDeleteTimerHandler(WMHandlerID handlerID)
234 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
236 if (!handler || !timerHandler)
237 return;
239 tmp = timerHandler;
241 handler->nextDelay = 0;
243 if (IS_ZERO(handler->when))
244 return;
246 if (tmp==handler) {
247 timerHandler = handler->next;
248 wfree(handler);
249 } else {
250 while (tmp->next) {
251 if (tmp->next==handler) {
252 tmp->next=handler->next;
253 wfree(handler);
254 break;
256 tmp = tmp->next;
263 WMHandlerID
264 WMAddIdleHandler(WMCallback *callback, void *cdata)
266 IdleHandler *handler;
268 handler = malloc(sizeof(IdleHandler));
269 if (!handler)
270 return NULL;
272 handler->callback = callback;
273 handler->clientData = cdata;
274 /* add handler at end of queue */
275 if (!idleHandler) {
276 idleHandler = WMCreateBag(16);
278 WMPutInBag(idleHandler, handler);
280 return handler;
284 void
285 WMDeleteIdleHandler(WMHandlerID handlerID)
287 IdleHandler *handler = (IdleHandler*)handlerID;
288 int pos;
290 if (!handler || !idleHandler)
291 return;
293 pos = WMGetFirstInBag(idleHandler, handler);
294 if (pos != WBNotFound) {
295 wfree(handler);
296 WMDeleteFromBag(idleHandler, pos);
302 WMHandlerID
303 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
305 InputHandler *handler;
307 handler = wmalloc(sizeof(InputHandler));
309 handler->fd = fd;
310 handler->mask = condition;
311 handler->callback = proc;
312 handler->clientData = clientData;
314 if (!inputHandler)
315 inputHandler = WMCreateBag(16);
316 WMPutInBag(inputHandler, handler);
318 return handler;
323 void
324 WMDeleteInputHandler(WMHandlerID handlerID)
326 InputHandler *handler = (InputHandler*)handlerID;
327 int pos;
329 if (!handler || !inputHandler)
330 return;
332 pos = WMGetFirstInBag(inputHandler, handler);
333 if (pos != WBNotFound) {
334 wfree(handler);
335 WMDeleteFromBag(inputHandler, pos);
341 static Bool
342 checkIdleHandlers()
344 IdleHandler *handler;
345 WMBag *handlerCopy;
346 WMBagIterator iter;
348 if (!idleHandler || WMGetBagItemCount(idleHandler)==0) {
349 W_FlushIdleNotificationQueue();
350 /* make sure an observer in queue didn't added an idle handler */
351 return (idleHandler!=NULL && WMGetBagItemCount(idleHandler)>0);
354 handlerCopy = WMCreateBag(WMGetBagItemCount(idleHandler));
355 WMAppendBag(handlerCopy, idleHandler);
357 for (handler = WMBagFirst(handlerCopy, &iter);
358 iter != NULL;
359 handler = WMBagNext(handlerCopy, &iter)) {
360 /* check if the handler still exist or was removed by a callback */
361 if (WMGetFirstInBag(idleHandler, handler) == WBNotFound)
362 continue;
364 (*handler->callback)(handler->clientData);
365 WMDeleteIdleHandler(handler);
368 WMFreeBag(handlerCopy);
370 W_FlushIdleNotificationQueue();
372 /* this is not necesarrily False, because one handler can re-add itself */
373 return (WMGetBagItemCount(idleHandler)>0);
378 static void
379 checkTimerHandlers()
381 TimerHandler *handler;
382 struct timeval now;
384 if (!timerHandler) {
385 W_FlushASAPNotificationQueue();
386 return;
389 rightNow(&now);
391 handler = timerHandler;
392 while (handler && IS_AFTER(now, handler->when)) {
393 if (!IS_ZERO(handler->when)) {
394 SET_ZERO(handler->when);
395 (*handler->callback)(handler->clientData);
397 handler = handler->next;
400 while (timerHandler && IS_ZERO(handler->when)) {
401 handler = timerHandler;
402 timerHandler = timerHandler->next;
404 if (handler->nextDelay > 0) {
405 handler->when = now;
406 addmillisecs(&handler->when, handler->nextDelay);
407 enqueueTimerHandler(handler);
408 } else {
409 wfree(handler);
413 W_FlushASAPNotificationQueue();
418 static void
419 delayUntilNextTimerEvent(struct timeval *delay)
421 struct timeval now;
422 TimerHandler *handler;
424 handler = timerHandler;
425 while (handler && IS_ZERO(handler->when)) handler = handler->next;
427 if (!handler) {
428 /* The return value of this function is only valid if there _are_
429 timers active. */
430 delay->tv_sec = 0;
431 delay->tv_usec = 0;
432 return;
435 rightNow(&now);
436 if (IS_AFTER(now, handler->when)) {
437 delay->tv_sec = 0;
438 delay->tv_usec = 0;
439 } else {
440 delay->tv_sec = handler->when.tv_sec - now.tv_sec;
441 delay->tv_usec = handler->when.tv_usec - now.tv_usec;
442 if (delay->tv_usec < 0) {
443 delay->tv_usec += 1000000;
444 delay->tv_sec--;
453 * WMCreateEventHandler--
454 * Create an event handler and put it in the event handler list for the
455 * view. If the same callback and clientdata are already used in another
456 * handler, the masks are swapped.
459 void
460 WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
461 void *clientData)
463 W_EventHandler *handler, *ptr;
464 unsigned long eventMask;
465 WMBagIterator iter;
468 handler = NULL;
469 eventMask = mask;
471 WM_ITERATE_BAG(view->eventHandlers, ptr, iter) {
472 if (ptr->clientData == clientData && ptr->proc == eventProc) {
473 handler = ptr;
474 eventMask |= ptr->eventMask;
477 if (!handler) {
478 handler = wmalloc(sizeof(W_EventHandler));
480 WMPutInBag(view->eventHandlers, handler);
482 /* select events for window */
483 handler->eventMask = eventMask;
484 handler->proc = eventProc;
485 handler->clientData = clientData;
490 * WMDeleteEventHandler--
491 * Delete event handler matching arguments from windows
492 * event handler list.
495 void
496 WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
497 void *clientData)
499 W_EventHandler *handler, *ptr;
500 WMBagIterator iter;
502 handler = NULL;
504 WM_ITERATE_BAG(view->eventHandlers, ptr, iter) {
505 if (ptr->eventMask == mask && ptr->proc == eventProc
506 && ptr->clientData == clientData) {
507 handler = ptr;
508 break;
512 if (!handler)
513 return;
515 WMRemoveFromBag(view->eventHandlers, handler);
517 wfree(handler);
522 void
523 W_CleanUpEvents(WMView *view)
525 W_EventHandler *ptr;
526 WMBagIterator iter;
528 WM_ITERATE_BAG(view->eventHandlers, ptr, iter) {
529 wfree(ptr);
535 static Time
536 getEventTime(WMScreen *screen, XEvent *event)
538 switch (event->type) {
539 case ButtonPress:
540 case ButtonRelease:
541 return event->xbutton.time;
542 case KeyPress:
543 case KeyRelease:
544 return event->xkey.time;
545 case MotionNotify:
546 return event->xmotion.time;
547 case EnterNotify:
548 case LeaveNotify:
549 return event->xcrossing.time;
550 case PropertyNotify:
551 return event->xproperty.time;
552 case SelectionClear:
553 return event->xselectionclear.time;
554 case SelectionRequest:
555 return event->xselectionrequest.time;
556 case SelectionNotify:
557 return event->xselection.time;
558 default:
559 return screen->lastEventTime;
564 void
565 W_CallDestroyHandlers(W_View *view)
567 XEvent event;
568 WMBagIterator iter;
569 W_EventHandler *hPtr;
571 event.type = DestroyNotify;
572 event.xdestroywindow.window = view->window;
573 event.xdestroywindow.event = view->window;
575 WM_ITERATE_BAG(view->eventHandlers, hPtr, iter) {
576 if (hPtr->eventMask & StructureNotifyMask) {
577 (*hPtr->proc)(&event, hPtr->clientData);
584 void
585 WMSetViewNextResponder(WMView *view, WMView *responder)
587 /* set the widget to receive keyboard events that aren't handled
588 * by this widget */
590 view->nextResponder = responder;
594 void
595 WMRelayToNextResponder(WMView *view, XEvent *event)
597 unsigned long mask = eventMasks[event->xany.type];
599 if (view->nextResponder) {
600 WMView *next = view->nextResponder;
601 W_EventHandler *hPtr;
602 WMBagIterator iter;
604 WM_ITERATE_BAG(next->eventHandlers, hPtr, iter) {
605 if ((hPtr->eventMask & mask)) {
606 (*hPtr->proc)(event, hPtr->clientData);
614 WMHandleEvent(XEvent *event)
616 W_EventHandler *hPtr;
617 W_View *view, *vPtr, *toplevel;
618 unsigned long mask;
619 Window window;
620 WMBagIterator iter;
622 if (event->type == MappingNotify) {
623 XRefreshKeyboardMapping(&event->xmapping);
624 return True;
627 mask = eventMasks[event->xany.type];
629 window = event->xany.window;
631 /* diferentiate SubstructureNotify with StructureNotify */
632 if (mask == StructureNotifyMask) {
633 if (event->xmap.event != event->xmap.window) {
634 mask = SubstructureNotifyMask;
635 window = event->xmap.event;
638 view = W_GetViewForXWindow(event->xany.display, window);
640 if (!view) {
641 if (extraEventHandler)
642 (extraEventHandler)(event);
644 return False;
647 view->screen->lastEventTime = getEventTime(view->screen, event);
649 toplevel = W_TopLevelOfView(view);
651 if (event->type == SelectionNotify || event->type == SelectionClear
652 || event->type == SelectionRequest) {
653 /* handle selection related events */
654 W_HandleSelectionEvent(event);
656 } else if (event->type == ClientMessage) {
658 W_HandleDNDClientMessage(toplevel, &event->xclient);
661 /* if it's a key event, redispatch it to the focused control */
662 if (mask & (KeyPressMask|KeyReleaseMask)) {
663 W_View *focused = W_FocusedViewOfToplevel(toplevel);
665 if (focused) {
666 view = focused;
670 /* compress Motion events */
671 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
672 while (XPending(event->xmotion.display)) {
673 XEvent ev;
674 XPeekEvent(event->xmotion.display, &ev);
675 if (ev.type == MotionNotify
676 && event->xmotion.window == ev.xmotion.window
677 && event->xmotion.subwindow == ev.xmotion.subwindow) {
678 /* replace events */
679 XNextEvent(event->xmotion.display, event);
680 } else break;
684 /* compress expose events */
685 if (event->type == Expose && !view->flags.dontCompressExpose) {
686 while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
687 Expose, event));
691 if (view->screen->modalLoop && toplevel!=view->screen->modalView
692 && !toplevel->flags.worksWhenModal) {
693 if (event->type == KeyPress || event->type == KeyRelease
694 || event->type == MotionNotify || event->type == ButtonPress
695 || event->type == ButtonRelease
696 || event->type == FocusIn || event->type == FocusOut) {
697 return True;
701 /* do balloon stuffs */
702 if (event->type == EnterNotify)
703 W_BalloonHandleEnterView(view);
704 else if (event->type == LeaveNotify)
705 W_BalloonHandleLeaveView(view);
707 /* This is a hack. It will make the panel be secure while
708 * the event handlers are handled, as some event handler
709 * might destroy the widget. */
710 W_RetainView(toplevel);
712 WM_ITERATE_BAG(view->eventHandlers, hPtr, iter) {
713 if ((hPtr->eventMask & mask)) {
714 (*hPtr->proc)(event, hPtr->clientData);
717 #if 0
718 /* pass the event to the top level window of the widget */
719 /* TODO: change this to a responder chain */
720 if (view->parent != NULL) {
721 vPtr = view;
722 while (vPtr->parent != NULL)
723 vPtr = vPtr->parent;
725 WM_ITERATE_BAG(vPtr->eventHandlers, hPtr, iter) {
726 if (hPtr->eventMask & mask) {
727 (*hPtr->proc)(event, hPtr->clientData);
731 #endif
732 /* save button click info to track double-clicks */
733 if (view->screen->ignoreNextDoubleClick) {
734 view->screen->ignoreNextDoubleClick = 0;
735 } else {
736 if (event->type == ButtonPress) {
737 view->screen->lastClickWindow = event->xbutton.window;
738 view->screen->lastClickTime = event->xbutton.time;
742 W_ReleaseView(toplevel);
744 return True;
749 WMIsDoubleClick(XEvent *event)
751 W_View *view;
753 if (event->type != ButtonPress)
754 return False;
756 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
758 if (!view)
759 return False;
761 if (view->screen->lastClickWindow != event->xbutton.window)
762 return False;
764 if (event->xbutton.time - view->screen->lastClickTime
765 < WINGsConfiguration.doubleClickDelay) {
766 view->screen->lastClickTime = 0;
767 view->screen->lastClickWindow = None;
768 view->screen->ignoreNextDoubleClick = 1;
769 return True;
770 } else
771 return False;
775 Bool
776 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
778 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
779 struct pollfd *fds;
780 InputHandler *handler;
781 int count, timeout, nfds, i, retval;
783 if (inputHandler)
784 nfds = WMGetBagItemCount(inputHandler);
785 else
786 nfds = 0;
788 fds = wmalloc(nfds+1 * sizeof(struct pollfd));
789 /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
790 fds[nfds].fd = ConnectionNumber(dpy);
791 fds[nfds].events = POLLIN;
793 for (i = 0; i<nfds; i++) {
794 handler = WMGetFromBag(inputHandler, i);
795 fds[i].fd = handler->fd;
796 fds[i].events = 0;
797 if (handler->mask & WIReadMask)
798 fds[i].events |= POLLIN;
800 if (handler->mask & WIWriteMask)
801 fds[i].events |= POLLOUT;
803 #if 0 /* FIXME */
804 if (handler->mask & WIExceptMask)
805 FD_SET(handler->fd, &eset);
806 #endif
810 * Setup the select() timeout to the estimated time until the
811 * next timer expires.
813 if (timerPending()) {
814 struct timeval tv;
815 delayUntilNextTimerEvent(&tv);
816 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
817 } else {
818 timeout = -1;
821 if (xeventmask==0) {
822 if (XPending(dpy))
823 return True;
824 } else {
825 XEvent ev;
826 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
827 XPutBackEvent(dpy, &ev);
828 return True;
832 count = poll(fds, nfds, timeout);
834 if (count>0 && nfds>0) {
835 WMBag *handlerCopy = WMCreateBag(nfds);
837 for (i=0; i<nfds; i++)
838 WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
840 for (i=0; i<nfds; i++) {
841 int mask;
843 handler = WMGetFromBag(handlerCopy, i);
844 /* check if the handler still exist or was removed by a callback */
845 if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
846 continue;
848 mask = 0;
850 if ((handler->mask & WIReadMask) &&
851 (fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
852 mask |= WIReadMask;
854 if ((handler->mask & WIWriteMask) &&
855 (fds[i].revents & (POLLOUT | POLLWRBAND)))
856 mask |= WIWriteMask;
858 if ((handler->mask & WIExceptMask) &&
859 (fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
860 mask |= WIExceptMask;
862 if (mask!=0 && handler->callback) {
863 (*handler->callback)(handler->fd, mask,
864 handler->clientData);
868 WMFreeBag(handlerCopy);
871 retval = fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
872 wfree(fds);
874 W_FlushASAPNotificationQueue();
876 return retval;
877 #else /* not HAVE_POLL */
878 #ifdef HAVE_SELECT
879 struct timeval timeout;
880 struct timeval *timeoutPtr;
881 fd_set rset, wset, eset;
882 int maxfd, nfds, i;
883 int count;
884 InputHandler *handler;
886 FD_ZERO(&rset);
887 FD_ZERO(&wset);
888 FD_ZERO(&eset);
890 FD_SET(ConnectionNumber(dpy), &rset);
891 maxfd = ConnectionNumber(dpy);
893 if (inputHandler)
894 nfds = WMGetBagItemCount(inputHandler);
895 else
896 nfds = 0;
898 for (i=0; i<nfds; i++) {
899 handler = WMGetFromBag(inputHandler, i);
900 if (handler->mask & WIReadMask)
901 FD_SET(handler->fd, &rset);
903 if (handler->mask & WIWriteMask)
904 FD_SET(handler->fd, &wset);
906 if (handler->mask & WIExceptMask)
907 FD_SET(handler->fd, &eset);
909 if (maxfd < handler->fd)
910 maxfd = handler->fd;
915 * Setup the select() timeout to the estimated time until the
916 * next timer expires.
918 if (timerPending()) {
919 delayUntilNextTimerEvent(&timeout);
920 timeoutPtr = &timeout;
921 } else {
922 timeoutPtr = (struct timeval*)0;
925 XSync(dpy, False);
926 if (xeventmask==0) {
927 if (XPending(dpy))
928 return True;
929 } else {
930 XEvent ev;
931 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
932 XPutBackEvent(dpy, &ev);
933 return True;
937 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
939 if (count>0 && nfds>0) {
940 WMBag *handlerCopy = WMCreateBag(nfds);
942 for (i=0; i<nfds; i++)
943 WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
945 for (i=0; i<nfds; i++) {
946 int mask;
948 handler = WMGetFromBag(handlerCopy, i);
949 /* check if the handler still exist or was removed by a callback */
950 if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
951 continue;
953 mask = 0;
955 if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
956 mask |= WIReadMask;
958 if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
959 mask |= WIWriteMask;
961 if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
962 mask |= WIExceptMask;
964 if (mask!=0 && handler->callback) {
965 (*handler->callback)(handler->fd, mask,
966 handler->clientData);
970 WMFreeBag(handlerCopy);
973 W_FlushASAPNotificationQueue();
975 return FD_ISSET(ConnectionNumber(dpy), &rset);
976 #else /* not HAVE_SELECT, not HAVE_POLL */
977 Neither select nor poll. You lose.
978 #endif /* HAVE_SELECT */
979 #endif /* HAVE_POLL */
983 void
984 WMNextEvent(Display *dpy, XEvent *event)
986 /* Check any expired timers */
987 checkTimerHandlers();
989 while (XPending(dpy) == 0) {
990 /* Do idle stuff */
991 /* Do idle and timer stuff while there are no timer or X events */
992 while (XPending(dpy) == 0 && checkIdleHandlers()) {
993 /* dispatch timer events */
994 checkTimerHandlers();
998 * Make sure that new events did not arrive while we were doing
999 * timer/idle stuff. Or we might block forever waiting for
1000 * an event that already arrived.
1002 /* wait for something to happen or a timer to expire */
1003 W_WaitForEvent(dpy, 0);
1005 /* Check any expired timers */
1006 checkTimerHandlers();
1009 XNextEvent(dpy, event);
1012 #if 0
1013 void
1014 WMMaskEvent(Display *dpy, long mask, XEvent *event)
1016 unsigned long milliseconds;
1017 struct timeval timeout;
1018 struct timeval *timeoutOrInfty;
1019 fd_set readset;
1021 while (!XCheckMaskEvent(dpy, mask, event)) {
1022 /* Do idle stuff while there are no timer or X events */
1023 while (checkIdleHandlers()) {
1024 if (XCheckMaskEvent(dpy, mask, event))
1025 return;
1029 * Setup the select() timeout to the estimated time until the
1030 * next timer expires.
1032 if (timerPending()) {
1033 delayUntilNextTimerEvent(&timeout);
1034 timeoutOrInfty = &timeout;
1035 } else {
1036 timeoutOrInfty = (struct timeval*)0;
1039 if (XCheckMaskEvent(dpy, mask, event))
1040 return;
1042 /* Wait for input on the X connection socket */
1043 FD_ZERO(&readset);
1044 FD_SET(ConnectionNumber(dpy), &readset);
1045 select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
1046 timeoutOrInfty);
1048 /* Check any expired timers */
1049 checkTimerHandlers();
1052 #endif
1053 #if 1
1055 * Cant use this because XPending() will make W_WaitForEvent
1056 * return even if the event in the queue is not what we want,
1057 * and if we block until some new event arrives from the
1058 * server, other events already in the queue (like Expose)
1059 * will be deferred.
1061 void
1062 WMMaskEvent(Display *dpy, long mask, XEvent *event)
1064 while (!XCheckMaskEvent(dpy, mask, event)) {
1065 /* Do idle stuff while there are no timer or X events */
1066 while (checkIdleHandlers()) {
1067 if (XCheckMaskEvent(dpy, mask, event))
1068 return;
1071 /* Wait for input on the X connection socket */
1072 W_WaitForEvent(dpy, mask);
1074 /* Check any expired timers */
1075 checkTimerHandlers();
1078 #endif
1080 Bool
1081 WMScreenPending(WMScreen *scr)
1083 if (XPending(scr->display))
1084 return True;
1085 else
1086 return False;
1090 WMEventHook*
1091 WMHookEventHandler(WMEventHook *handler)
1093 WMEventHook *oldHandler = extraEventHandler;
1095 extraEventHandler = handler;
1097 return oldHandler;