Added some () and a comment.
[wmaker-crm.git] / WINGs / wevent.c
blob488d611aeeb81cba34629ff67b1c0ecf5b744db5
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 W_FlushIdleNotificationQueue();
331 /* make sure an observer in queue didn't added an idle handler */
332 return (idleHandler!=NULL);
335 handler = idleHandler;
337 /* we will process all idleHandlers so, empty the handler list */
338 idleHandler = NULL;
340 while (handler) {
341 tmp = handler->next;
342 (*handler->callback)(handler->clientData);
343 /* remove the handler */
344 wfree(handler);
346 handler = tmp;
349 W_FlushIdleNotificationQueue();
351 /* this is not necesarrily False, because one handler can re-add itself */
352 return (idleHandler!=NULL);
357 static void
358 checkTimerHandlers()
360 TimerHandler *handler;
361 struct timeval now;
363 if (!timerHandler) {
364 W_FlushASAPNotificationQueue();
365 return;
368 rightNow(&now);
370 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
371 handler = timerHandler;
372 timerHandler = timerHandler->next;
373 handler->next = NULL;
374 (*handler->callback)(handler->clientData);
375 wfree(handler);
378 W_FlushASAPNotificationQueue();
383 static void
384 delayUntilNextTimerEvent(struct timeval *delay)
386 struct timeval now;
388 if (!timerHandler) {
389 /* The return value of this function is only valid if there _are_
390 timers active. */
391 delay->tv_sec = 0;
392 delay->tv_usec = 0;
393 return;
396 rightNow(&now);
397 if (IS_AFTER(now, timerHandler->when)) {
398 delay->tv_sec = 0;
399 delay->tv_usec = 0;
400 } else {
401 delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
402 delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
403 if (delay->tv_usec < 0) {
404 delay->tv_usec += 1000000;
405 delay->tv_sec--;
414 * WMCreateEventHandler--
415 * Create an event handler and put it in the event handler list for the
416 * view. If the same callback and clientdata are already used in another
417 * handler, the masks are swapped.
420 void
421 WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
422 void *clientData)
424 W_EventHandler *handler;
425 W_EventHandler *ptr = view->handlerList;
426 unsigned long eventMask;
428 if (ptr==NULL) {
429 handler = wmalloc(sizeof(W_EventHandler));
431 handler->nextHandler = NULL;
433 view->handlerList = handler;
435 eventMask = mask;
436 } else {
437 handler = NULL;
438 eventMask = mask;
439 while (ptr != NULL) {
440 if (ptr->clientData == clientData && ptr->proc == eventProc) {
441 handler = ptr;
443 eventMask |= ptr->eventMask;
445 ptr = ptr->nextHandler;
447 if (!handler) {
448 handler = wmalloc(sizeof(W_EventHandler));
449 handler->nextHandler = view->handlerList;
450 view->handlerList = handler;
454 /* select events for window */
455 handler->eventMask = mask;
456 handler->proc = eventProc;
457 handler->clientData = clientData;
462 * WMDeleteEventHandler--
463 * Delete event handler matching arguments from windows
464 * event handler list.
467 void
468 WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
469 void *clientData)
471 W_EventHandler *handler, *ptr, *pptr;
473 ptr = view->handlerList;
475 handler = NULL;
476 pptr = NULL;
478 while (ptr!=NULL) {
479 if (ptr->eventMask == mask && ptr->proc == eventProc
480 && ptr->clientData == clientData) {
481 handler = ptr;
482 break;
484 pptr = ptr;
485 ptr = ptr->nextHandler;
488 if (!handler)
489 return;
491 if (!pptr) {
492 view->handlerList = handler->nextHandler;
493 } else {
494 pptr->nextHandler = handler->nextHandler;
496 wfree(handler);
501 void
502 W_CleanUpEvents(WMView *view)
504 W_EventHandler *ptr, *nptr;
506 ptr = view->handlerList;
508 while (ptr!=NULL) {
509 nptr = ptr->nextHandler;
510 wfree(ptr);
511 ptr = nptr;
517 static Time
518 getEventTime(WMScreen *screen, XEvent *event)
520 switch (event->type) {
521 case ButtonPress:
522 case ButtonRelease:
523 return event->xbutton.time;
524 case KeyPress:
525 case KeyRelease:
526 return event->xkey.time;
527 case MotionNotify:
528 return event->xmotion.time;
529 case EnterNotify:
530 case LeaveNotify:
531 return event->xcrossing.time;
532 case PropertyNotify:
533 return event->xproperty.time;
534 case SelectionClear:
535 return event->xselectionclear.time;
536 case SelectionRequest:
537 return event->xselectionrequest.time;
538 case SelectionNotify:
539 return event->xselection.time;
540 default:
541 return screen->lastEventTime;
546 void
547 W_CallDestroyHandlers(W_View *view)
549 XEvent event;
550 W_EventHandler *hPtr;
552 event.type = DestroyNotify;
553 event.xdestroywindow.window = view->window;
554 event.xdestroywindow.event = view->window;
555 hPtr = view->handlerList;
556 while (hPtr!=NULL) {
557 if (hPtr->eventMask & StructureNotifyMask) {
558 (*hPtr->proc)(&event, hPtr->clientData);
561 hPtr = hPtr->nextHandler;
567 WMHandleEvent(XEvent *event)
569 W_EventHandler *hPtr;
570 W_View *view, *vPtr, *toplevel;
571 unsigned long mask;
572 Window window;
574 if (event->type == MappingNotify) {
575 XRefreshKeyboardMapping(&event->xmapping);
576 return True;
579 mask = eventMasks[event->xany.type];
581 window = event->xany.window;
583 /* diferentiate SubstructureNotify with StructureNotify */
584 if (mask == StructureNotifyMask) {
585 if (event->xmap.event != event->xmap.window) {
586 mask = SubstructureNotifyMask;
587 window = event->xmap.event;
590 view = W_GetViewForXWindow(event->xany.display, window);
591 if (!view) {
592 if (extraEventHandler)
593 (extraEventHandler)(event);
595 return False;
598 view->screen->lastEventTime = getEventTime(view->screen, event);
600 toplevel = W_TopLevelOfView(view);
602 if (event->type == SelectionNotify || event->type == SelectionClear
603 || event->type == SelectionRequest) {
604 /* handle selection related events */
605 W_HandleSelectionEvent(event);
608 /* if it's a key event, redispatch it to the focused control */
609 if (mask & (KeyPressMask|KeyReleaseMask)) {
610 W_View *focused = W_FocusedViewOfToplevel(toplevel);
612 if (focused) {
613 view = focused;
617 /* compress Motion events */
618 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
619 while (XPending(event->xmotion.display)) {
620 XEvent ev;
621 XPeekEvent(event->xmotion.display, &ev);
622 if (ev.type == MotionNotify
623 && event->xmotion.window == ev.xmotion.window
624 && event->xmotion.subwindow == ev.xmotion.subwindow) {
625 /* replace events */
626 XNextEvent(event->xmotion.display, event);
627 } else break;
631 /* compress expose events */
632 if (event->type == Expose && !view->flags.dontCompressExpose) {
633 while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
634 Expose, event));
638 if (view->screen->modal && toplevel!=view->screen->modalView
639 && !toplevel->flags.worksWhenModal) {
640 if (event->type == KeyPress || event->type == KeyRelease
641 || event->type == MotionNotify || event->type == ButtonPress
642 || event->type == ButtonRelease
643 || event->type == FocusIn || event->type == FocusOut) {
644 return True;
648 /* do balloon stuffs */
649 if (event->type == EnterNotify)
650 W_BalloonHandleEnterView(view);
651 else if (event->type == LeaveNotify)
652 W_BalloonHandleLeaveView(view);
654 /* This is a hack. It will make the panel be secure while
655 * the event handlers are handled, as some event handler
656 * might destroy the widget. */
657 W_RetainView(toplevel);
659 hPtr = view->handlerList;
661 while (hPtr!=NULL) {
662 W_EventHandler *tmp;
664 tmp = hPtr->nextHandler;
666 if ((hPtr->eventMask & mask)) {
667 (*hPtr->proc)(event, hPtr->clientData);
670 hPtr = tmp;
673 /* pass the event to the top level window of the widget */
674 if (view->parent!=NULL) {
675 vPtr = view;
676 while (vPtr->parent!=NULL)
677 vPtr = vPtr->parent;
679 hPtr = vPtr->handlerList;
681 while (hPtr!=NULL) {
683 if (hPtr->eventMask & mask) {
684 (*hPtr->proc)(event, hPtr->clientData);
686 hPtr = hPtr->nextHandler;
690 /* save button click info to track double-clicks */
691 if (view->screen->ignoreNextDoubleClick) {
692 view->screen->ignoreNextDoubleClick = 0;
693 } else {
694 if (event->type == ButtonPress) {
695 view->screen->lastClickWindow = event->xbutton.window;
696 view->screen->lastClickTime = event->xbutton.time;
700 W_ReleaseView(toplevel);
702 return True;
707 WMIsDoubleClick(XEvent *event)
709 W_View *view;
711 if (event->type != ButtonPress)
712 return False;
714 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
716 if (!view)
717 return False;
719 if (view->screen->lastClickWindow != event->xbutton.window)
720 return False;
722 if (event->xbutton.time - view->screen->lastClickTime
723 < WINGsConfiguration.doubleClickDelay) {
724 view->screen->lastClickTime = 0;
725 view->screen->lastClickWindow = None;
726 view->screen->ignoreNextDoubleClick = 1;
727 return True;
728 } else
729 return False;
733 Bool
734 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
736 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
737 struct pollfd *fds;
738 InputHandler *handler;
739 int count, timeout, nfds, k, retval;
741 for (nfds = 1, handler = inputHandler;
742 handler != 0; handler = handler->next) nfds++;
744 fds = wmalloc(nfds * sizeof(struct pollfd));
745 fds[0].fd = ConnectionNumber(dpy);
746 fds[0].events = POLLIN;
748 for (k = 1, handler = inputHandler;
749 handler;
750 handler = handler->next, k++) {
751 fds[k].fd = handler->fd;
752 fds[k].events = 0;
753 if (handler->mask & WIReadMask)
754 fds[k].events |= POLLIN;
756 if (handler->mask & WIWriteMask)
757 fds[k].events |= POLLOUT;
759 #if 0 /* FIXME */
760 if (handler->mask & WIExceptMask)
761 FD_SET(handler->fd, &eset);
762 #endif
766 * Setup the select() timeout to the estimated time until the
767 * next timer expires.
769 if (timerPending()) {
770 struct timeval tv;
771 delayUntilNextTimerEvent(&tv);
772 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
773 } else {
774 timeout = -1;
777 if (xeventmask==0) {
778 if (XPending(dpy))
779 return True;
780 } else {
781 XEvent ev;
782 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
783 XPutBackEvent(dpy, &ev);
784 return True;
788 count = poll(fds, nfds, timeout);
790 if (count > 0) {
791 handler = inputHandler;
792 k = 1;
793 while (handler) {
794 int mask;
795 InputHandler *next;
797 mask = 0;
799 if ((handler->mask & WIReadMask) &&
800 (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
801 mask |= WIReadMask;
803 if ((handler->mask & WIWriteMask) &&
804 (fds[k].revents & (POLLOUT | POLLWRBAND)))
805 mask |= WIWriteMask;
807 if ((handler->mask & WIExceptMask) &&
808 (fds[k].revents & (POLLHUP | POLLNVAL | POLLERR)))
809 mask |= WIExceptMask;
811 next = handler->next;
813 if (mask!=0 && handler->callback) {
814 (*handler->callback)(handler->fd, mask,
815 handler->clientData);
818 handler = next;
819 k++;
823 retval = fds[0].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
824 wfree(fds);
826 W_FlushASAPNotificationQueue();
828 return retval;
829 #else /* not HAVE_POLL */
830 #ifdef HAVE_SELECT
831 struct timeval timeout;
832 struct timeval *timeoutPtr;
833 fd_set rset, wset, eset;
834 int maxfd;
835 int count;
836 InputHandler *handler = inputHandler;
838 FD_ZERO(&rset);
839 FD_ZERO(&wset);
840 FD_ZERO(&eset);
842 FD_SET(ConnectionNumber(dpy), &rset);
843 maxfd = ConnectionNumber(dpy);
845 while (handler) {
846 if (handler->mask & WIReadMask)
847 FD_SET(handler->fd, &rset);
849 if (handler->mask & WIWriteMask)
850 FD_SET(handler->fd, &wset);
852 if (handler->mask & WIExceptMask)
853 FD_SET(handler->fd, &eset);
855 if (maxfd < handler->fd)
856 maxfd = handler->fd;
858 handler = handler->next;
863 * Setup the select() timeout to the estimated time until the
864 * next timer expires.
866 if (timerPending()) {
867 delayUntilNextTimerEvent(&timeout);
868 timeoutPtr = &timeout;
869 } else {
870 timeoutPtr = (struct timeval*)0;
873 XSync(dpy, False);
874 if (xeventmask==0) {
875 if (XPending(dpy))
876 return True;
877 } else {
878 XEvent ev;
879 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
880 XPutBackEvent(dpy, &ev);
881 return True;
885 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
887 if (count > 0) {
888 handler = inputHandler;
890 while (handler) {
891 int mask;
892 InputHandler *next;
894 mask = 0;
896 if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
897 mask |= WIReadMask;
899 if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
900 mask |= WIWriteMask;
902 if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
903 mask |= WIExceptMask;
905 /* save it because the handler may remove itself! */
906 next = handler->next;
908 if (mask!=0 && handler->callback) {
909 (*handler->callback)(handler->fd, mask,
910 handler->clientData);
913 handler = next;
917 W_FlushASAPNotificationQueue();
919 return FD_ISSET(ConnectionNumber(dpy), &rset);
920 #else /* not HAVE_SELECT, not HAVE_POLL */
921 Neither select nor poll. You lose.
922 #endif /* HAVE_SELECT */
923 #endif /* HAVE_POLL */
927 void
928 WMNextEvent(Display *dpy, XEvent *event)
930 /* Check any expired timers */
931 checkTimerHandlers();
933 while (XPending(dpy) == 0) {
934 /* Do idle stuff */
935 /* Do idle and timer stuff while there are no timer or X events */
936 while (!XPending(dpy) && checkIdleHandlers()) {
937 /* dispatch timer events */
938 checkTimerHandlers();
942 * Make sure that new events did not arrive while we were doing
943 * timer/idle stuff. Or we might block forever waiting for
944 * an event that already arrived.
946 /* wait to something happen */
947 W_WaitForEvent(dpy, 0);
949 /* Check any expired timers */
950 checkTimerHandlers();
953 XNextEvent(dpy, event);
956 #if 0
957 void
958 WMMaskEvent(Display *dpy, long mask, XEvent *event)
960 unsigned long milliseconds;
961 struct timeval timeout;
962 struct timeval *timeoutOrInfty;
963 fd_set readset;
965 while (!XCheckMaskEvent(dpy, mask, event)) {
966 /* Do idle stuff while there are no timer or X events */
967 while (checkIdleHandlers()) {
968 if (XCheckMaskEvent(dpy, mask, event))
969 return;
973 * Setup the select() timeout to the estimated time until the
974 * next timer expires.
976 if (timerPending()) {
977 delayUntilNextTimerEvent(&timeout);
978 timeoutOrInfty = &timeout;
979 } else {
980 timeoutOrInfty = (struct timeval*)0;
983 if (XCheckMaskEvent(dpy, mask, event))
984 return;
986 /* Wait for input on the X connection socket */
987 FD_ZERO(&readset);
988 FD_SET(ConnectionNumber(dpy), &readset);
989 select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
990 timeoutOrInfty);
992 /* Check any expired timers */
993 checkTimerHandlers();
996 #endif
997 #if 1
999 * Cant use this because XPending() will make W_WaitForEvent
1000 * return even if the event in the queue is not what we want,
1001 * and if we block until some new event arrives from the
1002 * server, other events already in the queue (like Expose)
1003 * will be deferred.
1005 void
1006 WMMaskEvent(Display *dpy, long mask, XEvent *event)
1008 while (!XCheckMaskEvent(dpy, mask, event)) {
1009 /* Do idle stuff while there are no timer or X events */
1010 while (checkIdleHandlers()) {
1011 if (XCheckMaskEvent(dpy, mask, event))
1012 return;
1015 /* Wait for input on the X connection socket */
1016 W_WaitForEvent(dpy, mask);
1018 /* Check any expired timers */
1019 checkTimerHandlers();
1022 #endif
1024 Bool
1025 WMScreenPending(WMScreen *scr)
1027 if (XPending(scr->display))
1028 return True;
1029 else
1030 return False;
1034 WMEventHook*
1035 WMHookEventHandler(WMEventHook *handler)
1037 WMEventHook *oldHandler = extraEventHandler;
1039 extraEventHandler = handler;
1041 return oldHandler;