fixed idle notification posting
[wmaker-crm.git] / WINGs / wevent.c
blob7d91e5d7911920d7f35f6a0693ce936fa8b9f935
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
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 } TimerHandler;
44 typedef struct IdleHandler {
45 WMCallback *callback;
46 void *clientData;
47 struct IdleHandler *next;
48 } IdleHandler;
51 typedef struct InputHandler {
52 WMInputProc *callback;
53 void *clientData;
54 int fd;
55 int mask;
56 struct InputHandler *next;
57 } InputHandler;
60 /* table to map event types to event masks */
61 static unsigned long eventMasks[] = {
64 KeyPressMask, /* KeyPress */
65 KeyReleaseMask, /* KeyRelease */
66 ButtonPressMask, /* ButtonPress */
67 ButtonReleaseMask, /* ButtonRelease */
68 PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
69 |Button1MotionMask|Button2MotionMask|Button3MotionMask
70 |Button4MotionMask|Button5MotionMask,
71 /* MotionNotify */
72 EnterWindowMask, /* EnterNotify */
73 LeaveWindowMask, /* LeaveNotify */
74 FocusChangeMask, /* FocusIn */
75 FocusChangeMask, /* FocusOut */
76 KeymapStateMask, /* KeymapNotify */
77 ExposureMask, /* Expose */
78 ExposureMask, /* GraphicsExpose */
79 ExposureMask, /* NoExpose */
80 VisibilityChangeMask, /* VisibilityNotify */
81 SubstructureNotifyMask, /* CreateNotify */
82 StructureNotifyMask, /* DestroyNotify */
83 StructureNotifyMask, /* UnmapNotify */
84 StructureNotifyMask, /* MapNotify */
85 SubstructureRedirectMask, /* MapRequest */
86 StructureNotifyMask, /* ReparentNotify */
87 StructureNotifyMask, /* ConfigureNotify */
88 SubstructureRedirectMask, /* ConfigureRequest */
89 StructureNotifyMask, /* GravityNotify */
90 ResizeRedirectMask, /* ResizeRequest */
91 StructureNotifyMask, /* CirculateNotify */
92 SubstructureRedirectMask, /* CirculateRequest */
93 PropertyChangeMask, /* PropertyNotify */
94 0, /* SelectionClear */
95 0, /* SelectionRequest */
96 0, /* SelectionNotify */
97 ColormapChangeMask, /* ColormapNotify */
98 ClientMessageMask, /* ClientMessage */
99 0, /* Mapping Notify */
104 /* queue of timer event handlers */
105 static TimerHandler *timerHandler=NULL;
107 static IdleHandler *idleHandler=NULL;
109 static InputHandler *inputHandler=NULL;
111 /* hook for other toolkits or wmaker process their events */
112 static WMEventHook *extraEventHandler=NULL;
116 #define timerPending() (timerHandler)
120 static void
121 rightNow(struct timeval *tv) {
122 X_GETTIMEOFDAY(tv);
125 /* is t1 after t2 ? */
126 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
127 (((t1).tv_sec == (t2).tv_sec) \
128 && ((t1).tv_usec > (t2).tv_usec)))
131 static void
132 addmillisecs(struct timeval *tv, int milliseconds)
134 tv->tv_usec += milliseconds*1000;
136 tv->tv_sec += tv->tv_usec/1000000;
137 tv->tv_usec = tv->tv_usec%1000000;
141 WMHandlerID
142 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
144 TimerHandler *handler, *tmp;
146 handler = malloc(sizeof(TimerHandler));
147 if (!handler)
148 return NULL;
150 rightNow(&handler->when);
151 addmillisecs(&handler->when, milliseconds);
152 handler->callback = callback;
153 handler->clientData = cdata;
154 /* insert callback in queue, sorted by time left */
155 if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
156 /* first in the queue */
157 handler->next = timerHandler;
158 timerHandler = handler;
159 } else {
160 tmp = timerHandler;
161 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
162 tmp = tmp->next;
164 handler->next = tmp->next;
165 tmp->next = handler;
167 return handler;
172 void
173 WMDeleteTimerWithClientData(void *cdata)
175 TimerHandler *handler, *tmp;
177 if (!cdata || !timerHandler)
178 return;
180 tmp = timerHandler;
181 if (tmp->clientData==cdata) {
182 timerHandler = tmp->next;
183 wfree(tmp);
184 } else {
185 while (tmp->next) {
186 if (tmp->next->clientData==cdata) {
187 handler = tmp->next;
188 tmp->next = handler->next;
189 wfree(handler);
190 break;
192 tmp = tmp->next;
199 void
200 WMDeleteTimerHandler(WMHandlerID handlerID)
202 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
204 if (!handler || !timerHandler)
205 return;
207 tmp = timerHandler;
208 if (tmp==handler) {
209 timerHandler = handler->next;
210 wfree(handler);
211 } else {
212 while (tmp->next) {
213 if (tmp->next==handler) {
214 tmp->next=handler->next;
215 wfree(handler);
216 break;
218 tmp = tmp->next;
225 WMHandlerID
226 WMAddIdleHandler(WMCallback *callback, void *cdata)
228 IdleHandler *handler, *tmp;
230 handler = malloc(sizeof(IdleHandler));
231 if (!handler)
232 return NULL;
234 handler->callback = callback;
235 handler->clientData = cdata;
236 handler->next = NULL;
237 /* add callback at end of queue */
238 if (!idleHandler) {
239 idleHandler = handler;
240 } else {
241 tmp = idleHandler;
242 while (tmp->next) {
243 tmp = tmp->next;
245 tmp->next = handler;
248 return handler;
253 void
254 WMDeleteIdleHandler(WMHandlerID handlerID)
256 IdleHandler *tmp, *handler = (IdleHandler*)handlerID;
258 if (!handler || !idleHandler)
259 return;
261 tmp = idleHandler;
262 if (tmp == handler) {
263 idleHandler = handler->next;
264 wfree(handler);
265 } else {
266 while (tmp->next) {
267 if (tmp->next == handler) {
268 tmp->next = handler->next;
269 wfree(handler);
270 break;
272 tmp = tmp->next;
279 WMHandlerID
280 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
282 InputHandler *handler;
284 handler = wmalloc(sizeof(InputHandler));
286 handler->fd = fd;
287 handler->mask = condition;
288 handler->callback = proc;
289 handler->clientData = clientData;
291 handler->next = inputHandler;
293 inputHandler = handler;
295 return handler;
299 void
300 WMDeleteInputHandler(WMHandlerID handlerID)
302 InputHandler *tmp, *handler = (InputHandler*)handlerID;
304 if (!handler || !inputHandler)
305 return;
307 tmp = inputHandler;
308 if (tmp == handler) {
309 inputHandler = handler->next;
310 wfree(handler);
311 } else {
312 while (tmp->next) {
313 if (tmp->next == handler) {
314 tmp->next = handler->next;
315 wfree(handler);
316 break;
318 tmp = tmp->next;
324 static Bool
325 checkIdleHandlers()
327 IdleHandler *handler, *tmp;
329 if (!idleHandler) {
330 return False;
333 handler = idleHandler;
335 /* we will process all idleHandlers so, empty the handler list */
336 idleHandler = NULL;
338 while (handler) {
339 tmp = handler->next;
340 (*handler->callback)(handler->clientData);
341 /* remove the handler */
342 wfree(handler);
344 handler = tmp;
347 return True;
352 static void
353 checkTimerHandlers()
355 TimerHandler *handler;
356 struct timeval now;
358 rightNow(&now);
360 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
361 handler = timerHandler;
362 timerHandler = timerHandler->next;
363 handler->next = NULL;
364 (*handler->callback)(handler->clientData);
365 wfree(handler);
368 W_FlushASAPNotificationQueue();
373 static void
374 delayUntilNextTimerEvent(struct timeval *delay)
376 struct timeval now;
378 if (!timerHandler) {
379 /* The return value of this function is only valid if there _are_
380 timers active. */
381 delay->tv_sec = 0;
382 delay->tv_usec = 0;
383 return;
386 rightNow(&now);
387 if (IS_AFTER(now, timerHandler->when)) {
388 delay->tv_sec = 0;
389 delay->tv_usec = 0;
390 } else {
391 delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
392 delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
393 if (delay->tv_usec < 0) {
394 delay->tv_usec += 1000000;
395 delay->tv_sec--;
404 * WMCreateEventHandler--
405 * Create an event handler and put it in the event handler list for the
406 * view. If the same callback and clientdata are already used in another
407 * handler, the masks are swapped.
410 void
411 WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
412 void *clientData)
414 W_EventHandler *handler;
415 W_EventHandler *ptr = view->handlerList;
416 unsigned long eventMask;
418 if (ptr==NULL) {
419 handler = wmalloc(sizeof(W_EventHandler));
421 handler->nextHandler = NULL;
423 view->handlerList = handler;
425 eventMask = mask;
426 } else {
427 handler = NULL;
428 eventMask = mask;
429 while (ptr != NULL) {
430 if (ptr->clientData == clientData && ptr->proc == eventProc) {
431 handler = ptr;
433 eventMask |= ptr->eventMask;
435 ptr = ptr->nextHandler;
437 if (!handler) {
438 handler = wmalloc(sizeof(W_EventHandler));
439 handler->nextHandler = view->handlerList;
440 view->handlerList = handler;
444 /* select events for window */
445 handler->eventMask = mask;
446 handler->proc = eventProc;
447 handler->clientData = clientData;
452 * WMDeleteEventHandler--
453 * Delete event handler matching arguments from windows
454 * event handler list.
457 void
458 WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
459 void *clientData)
461 W_EventHandler *handler, *ptr, *pptr;
463 ptr = view->handlerList;
465 handler = NULL;
466 pptr = NULL;
468 while (ptr!=NULL) {
469 if (ptr->eventMask == mask && ptr->proc == eventProc
470 && ptr->clientData == clientData) {
471 handler = ptr;
472 break;
474 pptr = ptr;
475 ptr = ptr->nextHandler;
478 if (!handler)
479 return;
481 if (!pptr) {
482 view->handlerList = handler->nextHandler;
483 } else {
484 pptr->nextHandler = handler->nextHandler;
486 wfree(handler);
491 void
492 W_CleanUpEvents(WMView *view)
494 W_EventHandler *ptr, *nptr;
496 ptr = view->handlerList;
498 while (ptr!=NULL) {
499 nptr = ptr->nextHandler;
500 wfree(ptr);
501 ptr = nptr;
507 static Time
508 getEventTime(WMScreen *screen, XEvent *event)
510 switch (event->type) {
511 case ButtonPress:
512 case ButtonRelease:
513 return event->xbutton.time;
514 case KeyPress:
515 case KeyRelease:
516 return event->xkey.time;
517 case MotionNotify:
518 return event->xmotion.time;
519 case EnterNotify:
520 case LeaveNotify:
521 return event->xcrossing.time;
522 case PropertyNotify:
523 return event->xproperty.time;
524 case SelectionClear:
525 return event->xselectionclear.time;
526 case SelectionRequest:
527 return event->xselectionrequest.time;
528 case SelectionNotify:
529 return event->xselection.time;
530 default:
531 return screen->lastEventTime;
536 void
537 W_CallDestroyHandlers(W_View *view)
539 XEvent event;
540 W_EventHandler *hPtr;
542 event.type = DestroyNotify;
543 event.xdestroywindow.window = view->window;
544 event.xdestroywindow.event = view->window;
545 hPtr = view->handlerList;
546 while (hPtr!=NULL) {
547 if (hPtr->eventMask & StructureNotifyMask) {
548 (*hPtr->proc)(&event, hPtr->clientData);
551 hPtr = hPtr->nextHandler;
557 WMHandleEvent(XEvent *event)
559 W_EventHandler *hPtr;
560 W_View *view, *vPtr, *toplevel;
561 unsigned long mask;
562 Window window;
564 if (event->type == MappingNotify) {
565 XRefreshKeyboardMapping(&event->xmapping);
566 return True;
569 mask = eventMasks[event->xany.type];
571 window = event->xany.window;
573 /* diferentiate SubstructureNotify with StructureNotify */
574 if (mask == StructureNotifyMask) {
575 if (event->xmap.event != event->xmap.window) {
576 mask = SubstructureNotifyMask;
577 window = event->xmap.event;
580 view = W_GetViewForXWindow(event->xany.display, window);
581 if (!view) {
582 if (extraEventHandler)
583 (extraEventHandler)(event);
585 return False;
588 view->screen->lastEventTime = getEventTime(view->screen, event);
590 toplevel = W_TopLevelOfView(view);
592 if (event->type == SelectionNotify || event->type == SelectionClear
593 || event->type == SelectionRequest) {
594 /* handle selection related events */
595 W_HandleSelectionEvent(event);
598 /* if it's a key event, redispatch it to the focused control */
599 if (mask & (KeyPressMask|KeyReleaseMask)) {
600 W_View *focused = W_FocusedViewOfToplevel(toplevel);
602 if (focused) {
603 view = focused;
607 /* compress Motion events */
608 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
609 while (XPending(event->xmotion.display)) {
610 XEvent ev;
611 XPeekEvent(event->xmotion.display, &ev);
612 if (ev.type == MotionNotify
613 && event->xmotion.window == ev.xmotion.window
614 && event->xmotion.subwindow == ev.xmotion.subwindow) {
615 /* replace events */
616 XNextEvent(event->xmotion.display, event);
617 } else break;
621 /* compress expose events */
622 if (event->type == Expose && !view->flags.dontCompressExpose) {
623 while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
624 Expose, event));
628 if (view->screen->modal && toplevel!=view->screen->modalView
629 && !toplevel->flags.worksWhenModal) {
630 if (event->type == KeyPress || event->type == KeyRelease
631 || event->type == MotionNotify || event->type == ButtonPress
632 || event->type == ButtonRelease
633 || event->type == FocusIn || event->type == FocusOut) {
634 return True;
638 /* do balloon stuffs */
639 if (event->type == EnterNotify)
640 W_BalloonHandleEnterView(view);
641 else if (event->type == LeaveNotify)
642 W_BalloonHandleLeaveView(view);
644 /* This is a hack. It will make the panel be secure while
645 * the event handlers are handled, as some event handler
646 * might destroy the widget. */
647 W_RetainView(toplevel);
649 hPtr = view->handlerList;
651 while (hPtr!=NULL) {
652 W_EventHandler *tmp;
654 tmp = hPtr->nextHandler;
656 if ((hPtr->eventMask & mask)) {
657 (*hPtr->proc)(event, hPtr->clientData);
660 hPtr = tmp;
663 /* pass the event to the top level window of the widget */
664 if (view->parent!=NULL) {
665 vPtr = view;
666 while (vPtr->parent!=NULL)
667 vPtr = vPtr->parent;
669 hPtr = vPtr->handlerList;
671 while (hPtr!=NULL) {
673 if (hPtr->eventMask & mask) {
674 (*hPtr->proc)(event, hPtr->clientData);
676 hPtr = hPtr->nextHandler;
680 /* save button click info to track double-clicks */
681 if (view->screen->ignoreNextDoubleClick) {
682 view->screen->ignoreNextDoubleClick = 0;
683 } else {
684 if (event->type == ButtonPress) {
685 view->screen->lastClickWindow = event->xbutton.window;
686 view->screen->lastClickTime = event->xbutton.time;
690 W_ReleaseView(toplevel);
692 return True;
697 WMIsDoubleClick(XEvent *event)
699 W_View *view;
701 if (event->type != ButtonPress)
702 return False;
704 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
706 if (!view)
707 return False;
709 if (view->screen->lastClickWindow != event->xbutton.window)
710 return False;
712 if (event->xbutton.time - view->screen->lastClickTime
713 < WINGsConfiguration.doubleClickDelay) {
714 view->screen->lastClickTime = 0;
715 view->screen->lastClickWindow = None;
716 view->screen->ignoreNextDoubleClick = 1;
717 return True;
718 } else
719 return False;
723 Bool
724 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
726 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
727 struct pollfd *fds;
728 InputHandler *handler;
729 int count, timeout, nfds, k, retval;
731 for (nfds = 1, handler = inputHandler;
732 handler != 0; handler = handler->next) nfds++;
734 fds = wmalloc(nfds * sizeof(struct pollfd));
735 fds[0].fd = ConnectionNumber(dpy);
736 fds[0].events = POLLIN;
738 for (k = 1, handler = inputHandler;
739 handler;
740 handler = handler->next, k++) {
741 fds[k].fd = handler->fd;
742 fds[k].events = 0;
743 if (handler->mask & WIReadMask)
744 fds[k].events |= POLLIN;
746 if (handler->mask & WIWriteMask)
747 fds[k].events |= POLLOUT;
749 #if 0 /* FIXME */
750 if (handler->mask & WIExceptMask)
751 FD_SET(handler->fd, &eset);
752 #endif
756 * Setup the select() timeout to the estimated time until the
757 * next timer expires.
759 if (timerPending()) {
760 struct timeval tv;
761 delayUntilNextTimerEvent(&tv);
762 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
763 } else {
764 timeout = -1;
767 if (xeventmask==0) {
768 if (XPending(dpy))
769 return True;
770 } else {
771 XEvent ev;
772 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
773 XPutBackEvent(dpy, &ev);
774 return True;
778 count = poll(fds, nfds, timeout);
780 if (count > 0) {
781 handler = inputHandler;
782 k = 1;
783 while (handler) {
784 int mask;
785 InputHandler *next;
787 mask = 0;
789 if (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI))
790 mask |= WIReadMask;
792 if (fds[k].revents & (POLLOUT | POLLWRBAND))
793 mask |= WIWriteMask;
795 if (fds[k].revents & (POLLHUP | POLLNVAL | POLLERR))
796 mask |= WIExceptMask;
798 next = handler->next;
800 if (mask!=0 && handler->callback) {
801 (*handler->callback)(handler->fd, mask,
802 handler->clientData);
805 handler = next;
806 k++;
810 retval = fds[0].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
811 wfree(fds);
813 W_FlushASAPNotificationQueue();
815 return retval;
816 #else /* not HAVE_POLL */
817 #ifdef HAVE_SELECT
818 struct timeval timeout;
819 struct timeval *timeoutPtr;
820 fd_set rset, wset, eset;
821 int maxfd;
822 int count;
823 InputHandler *handler = inputHandler;
825 FD_ZERO(&rset);
826 FD_ZERO(&wset);
827 FD_ZERO(&eset);
829 FD_SET(ConnectionNumber(dpy), &rset);
830 maxfd = ConnectionNumber(dpy);
832 while (handler) {
833 if (handler->mask & WIReadMask)
834 FD_SET(handler->fd, &rset);
836 if (handler->mask & WIWriteMask)
837 FD_SET(handler->fd, &wset);
839 if (handler->mask & WIExceptMask)
840 FD_SET(handler->fd, &eset);
842 if (maxfd < handler->fd)
843 maxfd = handler->fd;
845 handler = handler->next;
850 * Setup the select() timeout to the estimated time until the
851 * next timer expires.
853 if (timerPending()) {
854 delayUntilNextTimerEvent(&timeout);
855 timeoutPtr = &timeout;
856 } else {
857 timeoutPtr = (struct timeval*)0;
860 XSync(dpy, False);
861 if (xeventmask==0) {
862 if (XPending(dpy))
863 return True;
864 } else {
865 XEvent ev;
866 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
867 XPutBackEvent(dpy, &ev);
868 return True;
872 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
874 if (count > 0) {
875 handler = inputHandler;
877 while (handler) {
878 int mask;
879 InputHandler *next;
881 mask = 0;
883 if (FD_ISSET(handler->fd, &rset))
884 mask |= WIReadMask;
886 if (FD_ISSET(handler->fd, &wset))
887 mask |= WIWriteMask;
889 if (FD_ISSET(handler->fd, &eset))
890 mask |= WIExceptMask;
892 next = handler->next;
894 if (mask!=0 && handler->callback) {
895 (*handler->callback)(handler->fd, mask,
896 handler->clientData);
899 handler = next;
903 W_FlushASAPNotificationQueue();
905 return FD_ISSET(ConnectionNumber(dpy), &rset);
906 #else /* not HAVE_SELECT, not HAVE_POLL */
907 Neither select nor poll. You lose.
908 #endif /* HAVE_SELECT */
909 #endif /* HAVE_POLL */
913 void
914 WMNextEvent(Display *dpy, XEvent *event)
916 /* Check any expired timers */
917 if (timerPending()) {
918 checkTimerHandlers();
921 while (XPending(dpy) == 0) {
922 /* Do idle stuff */
923 /* Do idle and timer stuff while there are no timer or X events */
924 while (!XPending(dpy) && checkIdleHandlers()) {
926 W_FlushIdleNotificationQueue();
928 /* dispatch timer events */
929 if (timerPending())
930 checkTimerHandlers();
934 * Make sure that new events did not arrive while we were doing
935 * timer/idle stuff. Or we might block forever waiting for
936 * an event that already arrived.
938 /* wait to something happen */
939 W_WaitForEvent(dpy, 0);
941 /* Check any expired timers */
942 if (timerPending()) {
943 checkTimerHandlers();
947 XNextEvent(dpy, event);
950 #if 0
951 void
952 WMMaskEvent(Display *dpy, long mask, XEvent *event)
954 unsigned long milliseconds;
955 struct timeval timeout;
956 struct timeval *timeoutOrInfty;
957 fd_set readset;
959 while (!XCheckMaskEvent(dpy, mask, event)) {
960 /* Do idle stuff while there are no timer or X events */
961 while (checkIdleHandlers()) {
963 W_FlushIdleNotificationQueue();
965 if (XCheckMaskEvent(dpy, mask, event))
966 return;
970 * Setup the select() timeout to the estimated time until the
971 * next timer expires.
973 if (timerPending()) {
974 delayUntilNextTimerEvent(&timeout);
975 timeoutOrInfty = &timeout;
976 } else {
977 timeoutOrInfty = (struct timeval*)0;
980 if (XCheckMaskEvent(dpy, mask, event))
981 return;
983 /* Wait for input on the X connection socket */
984 FD_ZERO(&readset);
985 FD_SET(ConnectionNumber(dpy), &readset);
986 select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
987 timeoutOrInfty);
989 /* Check any expired timers */
990 if (timerPending()) {
991 checkTimerHandlers();
995 #endif
996 #if 1
998 * Cant use this because XPending() will make W_WaitForEvent
999 * return even if the event in the queue is not what we want,
1000 * and if we block until some new event arrives from the
1001 * server, other events already in the queue (like Expose)
1002 * will be deferred.
1004 void
1005 WMMaskEvent(Display *dpy, long mask, XEvent *event)
1007 while (!XCheckMaskEvent(dpy, mask, event)) {
1008 /* Do idle stuff while there are no timer or X events */
1009 while (checkIdleHandlers()) {
1011 W_FlushIdleNotificationQueue();
1013 if (XCheckMaskEvent(dpy, mask, event))
1014 return;
1017 /* Wait for input on the X connection socket */
1018 W_WaitForEvent(dpy, mask);
1020 /* Check any expired timers */
1021 if (timerPending()) {
1022 checkTimerHandlers();
1026 #endif
1028 Bool
1029 WMScreenPending(WMScreen *scr)
1031 if (XPending(scr->display))
1032 return True;
1033 else
1034 return False;
1038 WMEventHook*
1039 WMHookEventHandler(WMEventHook *handler)
1041 WMEventHook *oldHandler = extraEventHandler;
1043 extraEventHandler = handler;
1045 return oldHandler;