fix buglet
[wmaker-crm.git] / WINGs / wevent.c
blob999d50c3d91c8803335904676dac029813b5ab89
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
33 extern _WINGsConfiguration WINGsConfiguration;
37 typedef struct TimerHandler {
38 WMCallback *callback; /* procedure to call */
39 struct timeval when; /* when to call the callback */
40 void *clientData;
41 struct TimerHandler *next;
42 } TimerHandler;
45 typedef struct IdleHandler {
46 WMCallback *callback;
47 void *clientData;
48 struct IdleHandler *next;
49 } IdleHandler;
52 typedef struct InputHandler {
53 WMInputProc *callback;
54 void *clientData;
55 int fd;
56 int mask;
57 struct InputHandler *next;
58 } InputHandler;
61 /* table to map event types to event masks */
62 static unsigned long eventMasks[] = {
65 KeyPressMask, /* KeyPress */
66 KeyReleaseMask, /* KeyRelease */
67 ButtonPressMask, /* ButtonPress */
68 ButtonReleaseMask, /* ButtonRelease */
69 PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
70 |Button1MotionMask|Button2MotionMask|Button3MotionMask
71 |Button4MotionMask|Button5MotionMask,
72 /* MotionNotify */
73 EnterWindowMask, /* EnterNotify */
74 LeaveWindowMask, /* LeaveNotify */
75 FocusChangeMask, /* FocusIn */
76 FocusChangeMask, /* FocusOut */
77 KeymapStateMask, /* KeymapNotify */
78 ExposureMask, /* Expose */
79 ExposureMask, /* GraphicsExpose */
80 ExposureMask, /* NoExpose */
81 VisibilityChangeMask, /* VisibilityNotify */
82 SubstructureNotifyMask, /* CreateNotify */
83 StructureNotifyMask, /* DestroyNotify */
84 StructureNotifyMask, /* UnmapNotify */
85 StructureNotifyMask, /* MapNotify */
86 SubstructureRedirectMask, /* MapRequest */
87 StructureNotifyMask, /* ReparentNotify */
88 StructureNotifyMask, /* ConfigureNotify */
89 SubstructureRedirectMask, /* ConfigureRequest */
90 StructureNotifyMask, /* GravityNotify */
91 ResizeRedirectMask, /* ResizeRequest */
92 StructureNotifyMask, /* CirculateNotify */
93 SubstructureRedirectMask, /* CirculateRequest */
94 PropertyChangeMask, /* PropertyNotify */
95 0, /* SelectionClear */
96 0, /* SelectionRequest */
97 0, /* SelectionNotify */
98 ColormapChangeMask, /* ColormapNotify */
99 ClientMessageMask, /* ClientMessage */
100 0, /* Mapping Notify */
105 /* queue of timer event handlers */
106 static TimerHandler *timerHandler=NULL;
108 static IdleHandler *idleHandler=NULL;
110 static InputHandler *inputHandler=NULL;
112 /* hook for other toolkits or wmaker process their events */
113 static WMEventHook *extraEventHandler=NULL;
117 #define timerPending() (timerHandler)
119 #define idlePending() (idleHandler)
122 static void
123 rightNow(struct timeval *tv) {
124 X_GETTIMEOFDAY(tv);
127 /* is t1 after t2 ? */
128 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
129 (((t1).tv_sec == (t2).tv_sec) \
130 && ((t1).tv_usec > (t2).tv_usec)))
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 WMHandlerID
144 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
146 TimerHandler *handler, *tmp;
148 handler = malloc(sizeof(TimerHandler));
149 if (!handler)
150 return NULL;
152 rightNow(&handler->when);
153 addmillisecs(&handler->when, milliseconds);
154 handler->callback = callback;
155 handler->clientData = cdata;
156 /* insert callback in queue, sorted by time left */
157 if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
158 /* first in the queue */
159 handler->next = timerHandler;
160 timerHandler = handler;
161 } else {
162 tmp = timerHandler;
163 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
164 tmp = tmp->next;
166 handler->next = tmp->next;
167 tmp->next = handler;
169 return handler;
174 void
175 WMDeleteTimerWithClientData(void *cdata)
177 TimerHandler *handler, *tmp;
179 if (!cdata || !timerHandler)
180 return;
182 tmp = timerHandler;
183 if (tmp->clientData==cdata) {
184 timerHandler = tmp->next;
185 free(tmp);
186 } else {
187 while (tmp->next) {
188 if (tmp->next->clientData==cdata) {
189 handler = tmp->next;
190 tmp->next = handler->next;
191 free(handler);
192 break;
194 tmp = tmp->next;
201 void
202 WMDeleteTimerHandler(WMHandlerID handlerID)
204 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
206 if (!handler || !timerHandler)
207 return;
209 tmp = timerHandler;
210 if (tmp==handler) {
211 timerHandler = handler->next;
212 free(handler);
213 } else {
214 while (tmp->next) {
215 if (tmp->next==handler) {
216 tmp->next=handler->next;
217 free(handler);
218 break;
220 tmp = tmp->next;
227 WMHandlerID
228 WMAddIdleHandler(WMCallback *callback, void *cdata)
230 IdleHandler *handler, *tmp;
232 handler = malloc(sizeof(IdleHandler));
233 if (!handler)
234 return NULL;
236 handler->callback = callback;
237 handler->clientData = cdata;
238 handler->next = NULL;
239 /* add callback at end of queue */
240 if (!idleHandler) {
241 idleHandler = handler;
242 } else {
243 tmp = idleHandler;
244 while (tmp->next) {
245 tmp = tmp->next;
247 tmp->next = handler;
250 return handler;
255 void
256 WMDeleteIdleHandler(WMHandlerID handlerID)
258 IdleHandler *tmp, *handler = (IdleHandler*)handlerID;
260 if (!handler || !idleHandler)
261 return;
263 tmp = idleHandler;
264 if (tmp == handler) {
265 idleHandler = handler->next;
266 free(handler);
267 } else {
268 while (tmp->next) {
269 if (tmp->next == handler) {
270 tmp->next = handler->next;
271 free(handler);
272 break;
274 tmp = tmp->next;
281 WMHandlerID
282 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
284 InputHandler *handler;
286 handler = wmalloc(sizeof(InputHandler));
288 handler->fd = fd;
289 handler->mask = condition;
290 handler->callback = proc;
291 handler->clientData = clientData;
293 handler->next = inputHandler;
295 inputHandler = handler;
297 return handler;
301 void
302 WMDeleteInputHandler(WMHandlerID handlerID)
304 InputHandler *tmp, *handler = (InputHandler*)handlerID;
306 if (!handler || !inputHandler)
307 return;
309 tmp = inputHandler;
310 if (tmp == handler) {
311 inputHandler = handler->next;
312 free(handler);
313 } else {
314 while (tmp->next) {
315 if (tmp->next == handler) {
316 tmp->next = handler->next;
317 free(handler);
318 break;
320 tmp = tmp->next;
326 static void
327 checkIdleHandlers()
329 IdleHandler *handler, *tmp;
331 if (!idleHandler) {
332 W_FlushIdleNotificationQueue();
333 return;
336 handler = idleHandler;
338 /* we will process all idleHandlers so, empty the handler list */
339 idleHandler = NULL;
341 while (handler) {
342 tmp = handler->next;
343 (*handler->callback)(handler->clientData);
344 /* remove the handler */
345 free(handler);
347 handler = tmp;
349 W_FlushIdleNotificationQueue();
354 static void
355 checkTimerHandlers()
357 TimerHandler *handler;
358 struct timeval now;
360 rightNow(&now);
362 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
363 handler = timerHandler;
364 timerHandler = timerHandler->next;
365 handler->next = NULL;
366 (*handler->callback)(handler->clientData);
367 free(handler);
370 W_FlushASAPNotificationQueue();
375 static void
376 delayUntilNextTimerEvent(struct timeval *delay)
378 struct timeval now;
380 if (!timerHandler) {
381 /* The return value of this function is only valid if there _are_
382 timers active. */
383 delay->tv_sec = 0;
384 delay->tv_usec = 0;
385 return;
388 rightNow(&now);
389 if (IS_AFTER(now, timerHandler->when)) {
390 delay->tv_sec = 0;
391 delay->tv_usec = 0;
392 } else {
393 delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
394 delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
395 if (delay->tv_usec < 0) {
396 delay->tv_usec += 1000000;
397 delay->tv_sec--;
406 * WMCreateEventHandler--
407 * Create an event handler and put it in the event handler list for the
408 * view. If the same callback and clientdata are already used in another
409 * handler, the masks are swapped.
412 void
413 WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
414 void *clientData)
416 W_EventHandler *handler;
417 W_EventHandler *ptr = view->handlerList;
418 unsigned long eventMask;
420 if (ptr==NULL) {
421 handler = wmalloc(sizeof(W_EventHandler));
423 handler->nextHandler = NULL;
425 view->handlerList = handler;
427 eventMask = mask;
428 } else {
429 handler = NULL;
430 eventMask = mask;
431 while (ptr != NULL) {
432 if (ptr->clientData == clientData && ptr->proc == eventProc) {
433 handler = ptr;
435 eventMask |= ptr->eventMask;
437 ptr = ptr->nextHandler;
439 if (!handler) {
440 handler = wmalloc(sizeof(W_EventHandler));
441 handler->nextHandler = view->handlerList;
442 view->handlerList = handler;
446 /* select events for window */
447 handler->eventMask = mask;
448 handler->proc = eventProc;
449 handler->clientData = clientData;
454 * WMDeleteEventHandler--
455 * Delete event handler matching arguments from windows
456 * event handler list.
459 void
460 WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
461 void *clientData)
463 W_EventHandler *handler, *ptr, *pptr;
465 ptr = view->handlerList;
467 handler = NULL;
468 pptr = NULL;
470 while (ptr!=NULL) {
471 if (ptr->eventMask == mask && ptr->proc == eventProc
472 && ptr->clientData == clientData) {
473 handler = ptr;
474 break;
476 pptr = ptr;
477 ptr = ptr->nextHandler;
480 if (!handler)
481 return;
483 if (!pptr) {
484 view->handlerList = handler->nextHandler;
485 } else {
486 pptr->nextHandler = handler->nextHandler;
488 free(handler);
493 void
494 W_CleanUpEvents(WMView *view)
496 W_EventHandler *ptr, *nptr;
498 ptr = view->handlerList;
500 while (ptr!=NULL) {
501 nptr = ptr->nextHandler;
502 free(ptr);
503 ptr = nptr;
509 static Time
510 getEventTime(WMScreen *screen, XEvent *event)
512 switch (event->type) {
513 case ButtonPress:
514 case ButtonRelease:
515 return event->xbutton.time;
516 case KeyPress:
517 case KeyRelease:
518 return event->xkey.time;
519 case MotionNotify:
520 return event->xmotion.time;
521 case EnterNotify:
522 case LeaveNotify:
523 return event->xcrossing.time;
524 case PropertyNotify:
525 return event->xproperty.time;
526 case SelectionClear:
527 return event->xselectionclear.time;
528 case SelectionRequest:
529 return event->xselectionrequest.time;
530 case SelectionNotify:
531 return event->xselection.time;
532 default:
533 return screen->lastEventTime;
538 void
539 W_CallDestroyHandlers(W_View *view)
541 XEvent event;
542 W_EventHandler *hPtr;
544 event.type = DestroyNotify;
545 event.xdestroywindow.window = view->window;
546 event.xdestroywindow.event = view->window;
547 hPtr = view->handlerList;
548 while (hPtr!=NULL) {
549 if (hPtr->eventMask & StructureNotifyMask) {
550 (*hPtr->proc)(&event, hPtr->clientData);
553 hPtr = hPtr->nextHandler;
559 WMHandleEvent(XEvent *event)
561 W_EventHandler *hPtr;
562 W_View *view, *vPtr, *toplevel;
563 unsigned long mask;
564 Window window;
566 if (event->type == MappingNotify) {
567 XRefreshKeyboardMapping(&event->xmapping);
568 return True;
571 mask = eventMasks[event->xany.type];
573 window = event->xany.window;
575 /* diferentiate SubstructureNotify with StructureNotify */
576 if (mask == StructureNotifyMask) {
577 if (event->xmap.event != event->xmap.window) {
578 mask = SubstructureNotifyMask;
579 window = event->xmap.event;
582 view = W_GetViewForXWindow(event->xany.display, window);
583 if (!view) {
584 if (extraEventHandler)
585 (extraEventHandler)(event);
587 return False;
590 view->screen->lastEventTime = getEventTime(view->screen, event);
592 toplevel = W_TopLevelOfView(view);
594 if (event->type == SelectionNotify || event->type == SelectionClear
595 || event->type == SelectionRequest) {
596 puts("REQREWQ");
597 /* handle selection related events */
598 W_HandleSelectionEvent(event);
601 /* if it's a key event, redispatch it to the focused control */
602 if (mask & (KeyPressMask|KeyReleaseMask)) {
603 W_View *focused = W_FocusedViewOfToplevel(toplevel);
605 if (focused) {
606 view = focused;
610 /* compress Motion events */
611 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
612 while (XPending(event->xmotion.display)) {
613 XEvent ev;
614 XPeekEvent(event->xmotion.display, &ev);
615 if (ev.type == MotionNotify
616 && event->xmotion.window == ev.xmotion.window
617 && event->xmotion.subwindow == ev.xmotion.subwindow) {
618 /* replace events */
619 XNextEvent(event->xmotion.display, event);
620 } else break;
624 /* compress expose events */
625 if (event->type == Expose && !view->flags.dontCompressExpose) {
626 while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
627 Expose, event));
631 if (view->screen->modal && toplevel!=view->screen->modalView
632 && !toplevel->flags.worksWhenModal) {
633 if (event->type == KeyPress || event->type == KeyRelease
634 || event->type == MotionNotify || event->type == ButtonPress
635 || event->type == ButtonRelease
636 || event->type == FocusIn || event->type == FocusOut) {
637 return True;
641 /* do balloon stuffs */
642 if (event->type == EnterNotify)
643 W_BalloonHandleEnterView(view);
644 else if (event->type == LeaveNotify)
645 W_BalloonHandleLeaveView(view);
647 /* This is a hack. It will make the panel be secure while
648 * the event handlers are handled, as some event handler
649 * might destroy the widget. */
650 W_RetainView(toplevel);
652 hPtr = view->handlerList;
654 while (hPtr!=NULL) {
655 W_EventHandler *tmp;
657 tmp = hPtr->nextHandler;
659 if ((hPtr->eventMask & mask)) {
660 (*hPtr->proc)(event, hPtr->clientData);
663 hPtr = tmp;
666 /* pass the event to the top level window of the widget */
667 if (view->parent!=NULL) {
668 vPtr = view;
669 while (vPtr->parent!=NULL)
670 vPtr = vPtr->parent;
672 hPtr = vPtr->handlerList;
674 while (hPtr!=NULL) {
676 if (hPtr->eventMask & mask) {
677 (*hPtr->proc)(event, hPtr->clientData);
679 hPtr = hPtr->nextHandler;
683 /* save button click info to track double-clicks */
684 if (view->screen->ignoreNextDoubleClick) {
685 view->screen->ignoreNextDoubleClick = 0;
686 } else {
687 if (event->type == ButtonPress) {
688 view->screen->lastClickWindow = event->xbutton.window;
689 view->screen->lastClickTime = event->xbutton.time;
693 W_ReleaseView(toplevel);
695 return True;
700 WMIsDoubleClick(XEvent *event)
702 W_View *view;
704 if (event->type != ButtonPress)
705 return False;
707 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
709 if (!view)
710 return False;
712 if (view->screen->lastClickWindow != event->xbutton.window)
713 return False;
715 if (event->xbutton.time - view->screen->lastClickTime
716 < WINGsConfiguration.doubleClickDelay) {
717 view->screen->lastClickTime = 0;
718 view->screen->lastClickWindow = None;
719 view->screen->ignoreNextDoubleClick = 1;
720 return True;
721 } else
722 return False;
726 Bool
727 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
729 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
730 struct pollfd *fds;
731 InputHandler *handler;
732 int count, timeout, nfds, k, retval;
734 for (nfds = 1, handler = inputHandler;
735 handler != 0; handler = handler->next) nfds++;
737 fds = wmalloc(nfds * sizeof(struct pollfd));
738 fds[0].fd = ConnectionNumber(dpy);
739 fds[0].events = POLLIN;
741 for (k = 1, handler = inputHandler;
742 handler;
743 handler = handler->next, k++) {
744 fds[k].fd = handler->fd;
745 fds[k].events = 0;
746 if (handler->mask & WIReadMask)
747 fds[k].events |= POLLIN;
749 if (handler->mask & WIWriteMask)
750 fds[k].events |= POLLOUT;
752 #if 0 /* FIXME */
753 if (handler->mask & WIExceptMask)
754 FD_SET(handler->fd, &eset);
755 #endif
759 * Setup the select() timeout to the estimated time until the
760 * next timer expires.
762 if (timerPending()) {
763 struct timeval tv;
764 delayUntilNextTimerEvent(&tv);
765 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
766 } else {
767 timeout = -1;
770 if (xeventmask==0) {
771 if (XPending(dpy))
772 return True;
773 } else {
774 XEvent ev;
775 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
776 XPutBackEvent(dpy, &ev);
777 return True;
781 count = poll(fds, nfds, timeout);
783 if (count > 0) {
784 handler = inputHandler;
785 k = 1;
786 while (handler) {
787 int mask;
789 mask = 0;
791 if (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI))
792 mask |= WIReadMask;
794 if (fds[k].revents & (POLLOUT | POLLWRBAND))
795 mask |= WIWriteMask;
797 if (fds[k].revents & (POLLHUP | POLLNVAL | POLLERR))
798 mask |= WIExceptMask;
800 if (mask!=0 && handler->callback) {
801 (*handler->callback)(handler->fd, mask,
802 handler->clientData);
805 handler = handler->next;
806 k++;
810 retval = fds[0].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
811 free(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;
880 mask = 0;
882 if (FD_ISSET(handler->fd, &rset))
883 mask |= WIReadMask;
885 if (FD_ISSET(handler->fd, &wset))
886 mask |= WIWriteMask;
888 if (FD_ISSET(handler->fd, &eset))
889 mask |= WIExceptMask;
891 if (mask!=0 && handler->callback) {
892 (*handler->callback)(handler->fd, mask,
893 handler->clientData);
896 handler = handler->next;
900 W_FlushASAPNotificationQueue();
902 return FD_ISSET(ConnectionNumber(dpy), &rset);
903 #else /* not HAVE_SELECT, not HAVE_POLL */
904 Neither select nor poll. You lose.
905 #endif /* HAVE_SELECT */
906 #endif /* HAVE_POLL */
910 void
911 WMNextEvent(Display *dpy, XEvent *event)
913 /* Check any expired timers */
914 if (timerPending()) {
915 checkTimerHandlers();
918 while (XPending(dpy) == 0) {
919 /* Do idle stuff */
920 /* Do idle and timer stuff while there are no timer or X events */
921 while (!XPending(dpy) && idlePending()) {
922 if (idlePending())
923 checkIdleHandlers();
924 /* dispatch timer events */
925 if (timerPending())
926 checkTimerHandlers();
930 * Make sure that new events did not arrive while we were doing
931 * timer/idle stuff. Or we might block forever waiting for
932 * an event that already arrived.
934 /* wait to something happen */
935 W_WaitForEvent(dpy, 0);
937 /* Check any expired timers */
938 if (timerPending()) {
939 checkTimerHandlers();
943 XNextEvent(dpy, event);
946 #if 0
947 void
948 WMMaskEvent(Display *dpy, long mask, XEvent *event)
950 unsigned long milliseconds;
951 struct timeval timeout;
952 struct timeval *timeoutOrInfty;
953 fd_set readset;
955 while (!XCheckMaskEvent(dpy, mask, event)) {
956 /* Do idle stuff while there are no timer or X events */
957 while (idlePending()) {
958 checkIdleHandlers();
959 if (XCheckMaskEvent(dpy, mask, event))
960 return;
964 * Setup the select() timeout to the estimated time until the
965 * next timer expires.
967 if (timerPending()) {
968 delayUntilNextTimerEvent(&timeout);
969 timeoutOrInfty = &timeout;
970 } else {
971 timeoutOrInfty = (struct timeval*)0;
974 if (XCheckMaskEvent(dpy, mask, event))
975 return;
977 /* Wait for input on the X connection socket */
978 FD_ZERO(&readset);
979 FD_SET(ConnectionNumber(dpy), &readset);
980 select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
981 timeoutOrInfty);
983 /* Check any expired timers */
984 if (timerPending()) {
985 checkTimerHandlers();
989 #endif
990 #if 1
992 * Cant use this because XPending() will make W_WaitForEvent
993 * return even if the event in the queue is not what we want,
994 * and if we block until some new event arrives from the
995 * server, other events already in the queue (like Expose)
996 * will be deferred.
998 void
999 WMMaskEvent(Display *dpy, long mask, XEvent *event)
1001 while (!XCheckMaskEvent(dpy, mask, event)) {
1002 /* Do idle stuff while there are no timer or X events */
1003 while (idlePending()) {
1004 checkIdleHandlers();
1005 if (XCheckMaskEvent(dpy, mask, event))
1006 return;
1009 /* Wait for input on the X connection socket */
1010 W_WaitForEvent(dpy, mask);
1012 /* Check any expired timers */
1013 if (timerPending()) {
1014 checkTimerHandlers();
1018 #endif
1020 Bool
1021 WMScreenPending(WMScreen *scr)
1023 if (XPending(scr->display))
1024 return True;
1025 else
1026 return False;
1030 WMEventHook*
1031 WMHookEventHandler(WMEventHook *handler)
1033 WMEventHook *oldHandler = extraEventHandler;
1035 extraEventHandler = handler;
1037 return oldHandler;