Rewrote idle and input handlers using WMBag to avoid a functional problem of
[wmaker-crm.git] / WINGs / wevent.c
blob894a9e4fd50e2256937525063ab228a898268954
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 } IdleHandler;
50 typedef struct InputHandler {
51 WMInputProc *callback;
52 void *clientData;
53 int fd;
54 int mask;
55 } InputHandler;
58 /* table to map event types to event masks */
59 static unsigned long eventMasks[] = {
62 KeyPressMask, /* KeyPress */
63 KeyReleaseMask, /* KeyRelease */
64 ButtonPressMask, /* ButtonPress */
65 ButtonReleaseMask, /* ButtonRelease */
66 PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
67 |Button1MotionMask|Button2MotionMask|Button3MotionMask
68 |Button4MotionMask|Button5MotionMask,
69 /* MotionNotify */
70 EnterWindowMask, /* EnterNotify */
71 LeaveWindowMask, /* LeaveNotify */
72 FocusChangeMask, /* FocusIn */
73 FocusChangeMask, /* FocusOut */
74 KeymapStateMask, /* KeymapNotify */
75 ExposureMask, /* Expose */
76 ExposureMask, /* GraphicsExpose */
77 ExposureMask, /* NoExpose */
78 VisibilityChangeMask, /* VisibilityNotify */
79 SubstructureNotifyMask, /* CreateNotify */
80 StructureNotifyMask, /* DestroyNotify */
81 StructureNotifyMask, /* UnmapNotify */
82 StructureNotifyMask, /* MapNotify */
83 SubstructureRedirectMask, /* MapRequest */
84 StructureNotifyMask, /* ReparentNotify */
85 StructureNotifyMask, /* ConfigureNotify */
86 SubstructureRedirectMask, /* ConfigureRequest */
87 StructureNotifyMask, /* GravityNotify */
88 ResizeRedirectMask, /* ResizeRequest */
89 StructureNotifyMask, /* CirculateNotify */
90 SubstructureRedirectMask, /* CirculateRequest */
91 PropertyChangeMask, /* PropertyNotify */
92 0, /* SelectionClear */
93 0, /* SelectionRequest */
94 0, /* SelectionNotify */
95 ColormapChangeMask, /* ColormapNotify */
96 ClientMessageMask, /* ClientMessage */
97 0, /* Mapping Notify */
102 /* queue of timer event handlers */
103 static TimerHandler *timerHandler=NULL;
105 static WMBag *idleHandler=NULL;
107 static WMBag *inputHandler=NULL;
109 /* hook for other toolkits or wmaker process their events */
110 static WMEventHook *extraEventHandler=NULL;
114 #define timerPending() (timerHandler)
118 static void
119 rightNow(struct timeval *tv) {
120 X_GETTIMEOFDAY(tv);
123 /* is t1 after t2 ? */
124 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
125 (((t1).tv_sec == (t2).tv_sec) \
126 && ((t1).tv_usec > (t2).tv_usec)))
129 static void
130 addmillisecs(struct timeval *tv, int milliseconds)
132 tv->tv_usec += milliseconds*1000;
134 tv->tv_sec += tv->tv_usec/1000000;
135 tv->tv_usec = tv->tv_usec%1000000;
139 WMHandlerID
140 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
142 TimerHandler *handler, *tmp;
144 handler = malloc(sizeof(TimerHandler));
145 if (!handler)
146 return NULL;
148 rightNow(&handler->when);
149 addmillisecs(&handler->when, milliseconds);
150 handler->callback = callback;
151 handler->clientData = cdata;
152 /* insert callback in queue, sorted by time left */
153 if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
154 /* first in the queue */
155 handler->next = timerHandler;
156 timerHandler = handler;
157 } else {
158 tmp = timerHandler;
159 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
160 tmp = tmp->next;
162 handler->next = tmp->next;
163 tmp->next = handler;
165 return handler;
170 void
171 WMDeleteTimerWithClientData(void *cdata)
173 TimerHandler *handler, *tmp;
175 if (!cdata || !timerHandler)
176 return;
178 tmp = timerHandler;
179 if (tmp->clientData==cdata) {
180 timerHandler = tmp->next;
181 wfree(tmp);
182 } else {
183 while (tmp->next) {
184 if (tmp->next->clientData==cdata) {
185 handler = tmp->next;
186 tmp->next = handler->next;
187 wfree(handler);
188 break;
190 tmp = tmp->next;
197 void
198 WMDeleteTimerHandler(WMHandlerID handlerID)
200 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
202 if (!handler || !timerHandler)
203 return;
205 tmp = timerHandler;
206 if (tmp==handler) {
207 timerHandler = handler->next;
208 wfree(handler);
209 } else {
210 while (tmp->next) {
211 if (tmp->next==handler) {
212 tmp->next=handler->next;
213 wfree(handler);
214 break;
216 tmp = tmp->next;
223 WMHandlerID
224 WMAddIdleHandler(WMCallback *callback, void *cdata)
226 IdleHandler *handler;
228 handler = malloc(sizeof(IdleHandler));
229 if (!handler)
230 return NULL;
232 handler->callback = callback;
233 handler->clientData = cdata;
234 /* add handler at end of queue */
235 if (!idleHandler) {
236 idleHandler = WMCreateBag(16);
238 WMPutInBag(idleHandler, handler);
240 return handler;
245 void
246 WMDeleteIdleHandler(WMHandlerID handlerID)
248 IdleHandler *handler = (IdleHandler*)handlerID;
249 int pos;
251 if (!handler || !idleHandler)
252 return;
254 pos = WMGetFirstInBag(idleHandler, handler);
255 if (pos >= 0) {
256 wfree(handler);
257 WMDeleteFromBag(idleHandler, pos);
263 WMHandlerID
264 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
266 InputHandler *handler;
268 handler = wmalloc(sizeof(InputHandler));
270 handler->fd = fd;
271 handler->mask = condition;
272 handler->callback = proc;
273 handler->clientData = clientData;
275 if (!inputHandler)
276 inputHandler = WMCreateBag(16);
277 WMPutInBag(inputHandler, handler);
279 return handler;
284 void
285 WMDeleteInputHandler(WMHandlerID handlerID)
287 InputHandler *handler = (InputHandler*)handlerID;
288 int pos;
290 if (!handler || !inputHandler)
291 return;
293 pos = WMGetFirstInBag(inputHandler, handler);
294 if (pos >= 0) {
295 wfree(handler);
296 WMDeleteFromBag(inputHandler, pos);
302 static Bool
303 checkIdleHandlers()
305 IdleHandler *handler;
306 WMBag *handlerCopy;
307 int i, n;
309 if (!idleHandler || WMGetBagItemCount(idleHandler)==0) {
310 W_FlushIdleNotificationQueue();
311 /* make sure an observer in queue didn't added an idle handler */
312 return (idleHandler!=NULL && WMGetBagItemCount(idleHandler)>0);
315 n = WMGetBagItemCount(idleHandler);
316 handlerCopy = WMCreateBag(n);
317 for (i=0; i<n; i++)
318 WMPutInBag(handlerCopy, WMGetFromBag(idleHandler, i));
320 for (i=0; i<n; i++) {
321 handler = WMGetFromBag(handlerCopy, i);
322 /* check if the handler still exist or was removed by a callback */
323 if (WMGetFirstInBag(idleHandler, handler)<0)
324 continue;
326 (*handler->callback)(handler->clientData);
327 WMDeleteIdleHandler(handler);
330 WMFreeBag(handlerCopy);
332 W_FlushIdleNotificationQueue();
334 /* this is not necesarrily False, because one handler can re-add itself */
335 return (WMGetBagItemCount(idleHandler)>0);
340 static void
341 checkTimerHandlers()
343 TimerHandler *handler;
344 struct timeval now;
346 if (!timerHandler) {
347 W_FlushASAPNotificationQueue();
348 return;
351 rightNow(&now);
353 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
354 handler = timerHandler;
355 timerHandler = timerHandler->next;
356 handler->next = NULL;
357 (*handler->callback)(handler->clientData);
358 wfree(handler);
361 W_FlushASAPNotificationQueue();
366 static void
367 delayUntilNextTimerEvent(struct timeval *delay)
369 struct timeval now;
371 if (!timerHandler) {
372 /* The return value of this function is only valid if there _are_
373 timers active. */
374 delay->tv_sec = 0;
375 delay->tv_usec = 0;
376 return;
379 rightNow(&now);
380 if (IS_AFTER(now, timerHandler->when)) {
381 delay->tv_sec = 0;
382 delay->tv_usec = 0;
383 } else {
384 delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
385 delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
386 if (delay->tv_usec < 0) {
387 delay->tv_usec += 1000000;
388 delay->tv_sec--;
397 * WMCreateEventHandler--
398 * Create an event handler and put it in the event handler list for the
399 * view. If the same callback and clientdata are already used in another
400 * handler, the masks are swapped.
403 void
404 WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
405 void *clientData)
407 W_EventHandler *handler;
408 W_EventHandler *ptr = view->handlerList;
409 unsigned long eventMask;
411 if (ptr==NULL) {
412 handler = wmalloc(sizeof(W_EventHandler));
414 handler->nextHandler = NULL;
416 view->handlerList = handler;
418 eventMask = mask;
419 } else {
420 handler = NULL;
421 eventMask = mask;
422 while (ptr != NULL) {
423 if (ptr->clientData == clientData && ptr->proc == eventProc) {
424 handler = ptr;
426 eventMask |= ptr->eventMask;
428 ptr = ptr->nextHandler;
430 if (!handler) {
431 handler = wmalloc(sizeof(W_EventHandler));
432 handler->nextHandler = view->handlerList;
433 view->handlerList = handler;
437 /* select events for window */
438 handler->eventMask = mask;
439 handler->proc = eventProc;
440 handler->clientData = clientData;
445 * WMDeleteEventHandler--
446 * Delete event handler matching arguments from windows
447 * event handler list.
450 void
451 WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
452 void *clientData)
454 W_EventHandler *handler, *ptr, *pptr;
456 ptr = view->handlerList;
458 handler = NULL;
459 pptr = NULL;
461 while (ptr!=NULL) {
462 if (ptr->eventMask == mask && ptr->proc == eventProc
463 && ptr->clientData == clientData) {
464 handler = ptr;
465 break;
467 pptr = ptr;
468 ptr = ptr->nextHandler;
471 if (!handler)
472 return;
474 if (!pptr) {
475 view->handlerList = handler->nextHandler;
476 } else {
477 pptr->nextHandler = handler->nextHandler;
479 wfree(handler);
484 void
485 W_CleanUpEvents(WMView *view)
487 W_EventHandler *ptr, *nptr;
489 ptr = view->handlerList;
491 while (ptr!=NULL) {
492 nptr = ptr->nextHandler;
493 wfree(ptr);
494 ptr = nptr;
500 static Time
501 getEventTime(WMScreen *screen, XEvent *event)
503 switch (event->type) {
504 case ButtonPress:
505 case ButtonRelease:
506 return event->xbutton.time;
507 case KeyPress:
508 case KeyRelease:
509 return event->xkey.time;
510 case MotionNotify:
511 return event->xmotion.time;
512 case EnterNotify:
513 case LeaveNotify:
514 return event->xcrossing.time;
515 case PropertyNotify:
516 return event->xproperty.time;
517 case SelectionClear:
518 return event->xselectionclear.time;
519 case SelectionRequest:
520 return event->xselectionrequest.time;
521 case SelectionNotify:
522 return event->xselection.time;
523 default:
524 return screen->lastEventTime;
529 void
530 W_CallDestroyHandlers(W_View *view)
532 XEvent event;
533 W_EventHandler *hPtr;
535 event.type = DestroyNotify;
536 event.xdestroywindow.window = view->window;
537 event.xdestroywindow.event = view->window;
538 hPtr = view->handlerList;
539 while (hPtr!=NULL) {
540 if (hPtr->eventMask & StructureNotifyMask) {
541 (*hPtr->proc)(&event, hPtr->clientData);
544 hPtr = hPtr->nextHandler;
550 WMHandleEvent(XEvent *event)
552 W_EventHandler *hPtr;
553 W_View *view, *vPtr, *toplevel;
554 unsigned long mask;
555 Window window;
557 if (event->type == MappingNotify) {
558 XRefreshKeyboardMapping(&event->xmapping);
559 return True;
562 mask = eventMasks[event->xany.type];
564 window = event->xany.window;
566 /* diferentiate SubstructureNotify with StructureNotify */
567 if (mask == StructureNotifyMask) {
568 if (event->xmap.event != event->xmap.window) {
569 mask = SubstructureNotifyMask;
570 window = event->xmap.event;
573 view = W_GetViewForXWindow(event->xany.display, window);
574 if (!view) {
575 if (extraEventHandler)
576 (extraEventHandler)(event);
578 return False;
581 view->screen->lastEventTime = getEventTime(view->screen, event);
583 toplevel = W_TopLevelOfView(view);
585 if (event->type == SelectionNotify || event->type == SelectionClear
586 || event->type == SelectionRequest) {
587 /* handle selection related events */
588 W_HandleSelectionEvent(event);
591 /* if it's a key event, redispatch it to the focused control */
592 if (mask & (KeyPressMask|KeyReleaseMask)) {
593 W_View *focused = W_FocusedViewOfToplevel(toplevel);
595 if (focused) {
596 view = focused;
600 /* compress Motion events */
601 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
602 while (XPending(event->xmotion.display)) {
603 XEvent ev;
604 XPeekEvent(event->xmotion.display, &ev);
605 if (ev.type == MotionNotify
606 && event->xmotion.window == ev.xmotion.window
607 && event->xmotion.subwindow == ev.xmotion.subwindow) {
608 /* replace events */
609 XNextEvent(event->xmotion.display, event);
610 } else break;
614 /* compress expose events */
615 if (event->type == Expose && !view->flags.dontCompressExpose) {
616 while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
617 Expose, event));
621 if (view->screen->modal && toplevel!=view->screen->modalView
622 && !toplevel->flags.worksWhenModal) {
623 if (event->type == KeyPress || event->type == KeyRelease
624 || event->type == MotionNotify || event->type == ButtonPress
625 || event->type == ButtonRelease
626 || event->type == FocusIn || event->type == FocusOut) {
627 return True;
631 /* do balloon stuffs */
632 if (event->type == EnterNotify)
633 W_BalloonHandleEnterView(view);
634 else if (event->type == LeaveNotify)
635 W_BalloonHandleLeaveView(view);
637 /* This is a hack. It will make the panel be secure while
638 * the event handlers are handled, as some event handler
639 * might destroy the widget. */
640 W_RetainView(toplevel);
642 hPtr = view->handlerList;
644 while (hPtr!=NULL) {
645 W_EventHandler *tmp;
647 tmp = hPtr->nextHandler;
649 if ((hPtr->eventMask & mask)) {
650 (*hPtr->proc)(event, hPtr->clientData);
653 hPtr = tmp;
656 /* pass the event to the top level window of the widget */
657 if (view->parent!=NULL) {
658 vPtr = view;
659 while (vPtr->parent!=NULL)
660 vPtr = vPtr->parent;
662 hPtr = vPtr->handlerList;
664 while (hPtr!=NULL) {
666 if (hPtr->eventMask & mask) {
667 (*hPtr->proc)(event, hPtr->clientData);
669 hPtr = hPtr->nextHandler;
673 /* save button click info to track double-clicks */
674 if (view->screen->ignoreNextDoubleClick) {
675 view->screen->ignoreNextDoubleClick = 0;
676 } else {
677 if (event->type == ButtonPress) {
678 view->screen->lastClickWindow = event->xbutton.window;
679 view->screen->lastClickTime = event->xbutton.time;
683 W_ReleaseView(toplevel);
685 return True;
690 WMIsDoubleClick(XEvent *event)
692 W_View *view;
694 if (event->type != ButtonPress)
695 return False;
697 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
699 if (!view)
700 return False;
702 if (view->screen->lastClickWindow != event->xbutton.window)
703 return False;
705 if (event->xbutton.time - view->screen->lastClickTime
706 < WINGsConfiguration.doubleClickDelay) {
707 view->screen->lastClickTime = 0;
708 view->screen->lastClickWindow = None;
709 view->screen->ignoreNextDoubleClick = 1;
710 return True;
711 } else
712 return False;
716 Bool
717 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
719 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
720 struct pollfd *fds;
721 InputHandler *handler;
722 int count, timeout, nfds, i, retval;
724 if (inputHandler)
725 nfds = WMGetBagItemCount(inputHandler);
726 else
727 nfds = 0;
729 fds = wmalloc(nfds+1 * sizeof(struct pollfd));
730 /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
731 fds[nfds].fd = ConnectionNumber(dpy);
732 fds[nfds].events = POLLIN;
734 for (i = 0; i<nfds; i++) {
735 handler = WMGetFromBag(inputHandler, i);
736 fds[i].fd = handler->fd;
737 fds[i].events = 0;
738 if (handler->mask & WIReadMask)
739 fds[i].events |= POLLIN;
741 if (handler->mask & WIWriteMask)
742 fds[i].events |= POLLOUT;
744 #if 0 /* FIXME */
745 if (handler->mask & WIExceptMask)
746 FD_SET(handler->fd, &eset);
747 #endif
751 * Setup the select() timeout to the estimated time until the
752 * next timer expires.
754 if (timerPending()) {
755 struct timeval tv;
756 delayUntilNextTimerEvent(&tv);
757 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
758 } else {
759 timeout = -1;
762 if (xeventmask==0) {
763 if (XPending(dpy))
764 return True;
765 } else {
766 XEvent ev;
767 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
768 XPutBackEvent(dpy, &ev);
769 return True;
773 count = poll(fds, nfds, timeout);
775 if (count>0 && nfds>0) {
776 WMBag *handlerCopy = WMCreateBag(nfds);
778 for (i=0; i<nfds; i++)
779 WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
781 for (i=0; i<nfds; i++) {
782 int mask;
784 handler = WMGetFromBag(handlerCopy, i);
785 /* check if the handler still exist or was removed by a callback */
786 if (WMGetFirstInBag(inputHandler, handler)<0)
787 continue;
789 mask = 0;
791 if ((handler->mask & WIReadMask) &&
792 (fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
793 mask |= WIReadMask;
795 if ((handler->mask & WIWriteMask) &&
796 (fds[i].revents & (POLLOUT | POLLWRBAND)))
797 mask |= WIWriteMask;
799 if ((handler->mask & WIExceptMask) &&
800 (fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
801 mask |= WIExceptMask;
803 if (mask!=0 && handler->callback) {
804 (*handler->callback)(handler->fd, mask,
805 handler->clientData);
809 WMFreeBag(handlerCopy);
812 retval = fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
813 wfree(fds);
815 W_FlushASAPNotificationQueue();
817 return retval;
818 #else /* not HAVE_POLL */
819 #ifdef HAVE_SELECT
820 struct timeval timeout;
821 struct timeval *timeoutPtr;
822 fd_set rset, wset, eset;
823 int maxfd, nfds, i;
824 int count;
825 InputHandler *handler;
827 FD_ZERO(&rset);
828 FD_ZERO(&wset);
829 FD_ZERO(&eset);
831 FD_SET(ConnectionNumber(dpy), &rset);
832 maxfd = ConnectionNumber(dpy);
834 if (inputHandler)
835 nfds = WMGetBagItemCount(inputHandler);
836 else
837 nfds = 0;
839 for (i=0; i<nfds; i++) {
840 handler = WMGetFromBag(inputHandler, i);
841 if (handler->mask & WIReadMask)
842 FD_SET(handler->fd, &rset);
844 if (handler->mask & WIWriteMask)
845 FD_SET(handler->fd, &wset);
847 if (handler->mask & WIExceptMask)
848 FD_SET(handler->fd, &eset);
850 if (maxfd < handler->fd)
851 maxfd = handler->fd;
856 * Setup the select() timeout to the estimated time until the
857 * next timer expires.
859 if (timerPending()) {
860 delayUntilNextTimerEvent(&timeout);
861 timeoutPtr = &timeout;
862 } else {
863 timeoutPtr = (struct timeval*)0;
866 XSync(dpy, False);
867 if (xeventmask==0) {
868 if (XPending(dpy))
869 return True;
870 } else {
871 XEvent ev;
872 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
873 XPutBackEvent(dpy, &ev);
874 return True;
878 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
880 if (count>0 && nfds>0) {
881 WMBag *handlerCopy = WMCreateBag(nfds);
883 for (i=0; i<nfds; i++)
884 WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
886 for (i=0; i<nfds; i++) {
887 int mask;
889 handler = WMGetFromBag(handlerCopy, i);
890 /* check if the handler still exist or was removed by a callback */
891 if (WMGetFirstInBag(inputHandler, handler)<0)
892 continue;
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 if (mask!=0 && handler->callback) {
906 (*handler->callback)(handler->fd, mask,
907 handler->clientData);
911 WMFreeBag(handlerCopy);
914 W_FlushASAPNotificationQueue();
916 return FD_ISSET(ConnectionNumber(dpy), &rset);
917 #else /* not HAVE_SELECT, not HAVE_POLL */
918 Neither select nor poll. You lose.
919 #endif /* HAVE_SELECT */
920 #endif /* HAVE_POLL */
924 void
925 WMNextEvent(Display *dpy, XEvent *event)
927 /* Check any expired timers */
928 checkTimerHandlers();
930 while (XPending(dpy) == 0) {
931 /* Do idle stuff */
932 /* Do idle and timer stuff while there are no timer or X events */
933 while (!XPending(dpy) && checkIdleHandlers()) {
934 /* dispatch timer events */
935 checkTimerHandlers();
939 * Make sure that new events did not arrive while we were doing
940 * timer/idle stuff. Or we might block forever waiting for
941 * an event that already arrived.
943 /* wait to something happen */
944 W_WaitForEvent(dpy, 0);
946 /* Check any expired timers */
947 checkTimerHandlers();
950 XNextEvent(dpy, event);
953 #if 0
954 void
955 WMMaskEvent(Display *dpy, long mask, XEvent *event)
957 unsigned long milliseconds;
958 struct timeval timeout;
959 struct timeval *timeoutOrInfty;
960 fd_set readset;
962 while (!XCheckMaskEvent(dpy, mask, event)) {
963 /* Do idle stuff while there are no timer or X events */
964 while (checkIdleHandlers()) {
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 checkTimerHandlers();
993 #endif
994 #if 1
996 * Cant use this because XPending() will make W_WaitForEvent
997 * return even if the event in the queue is not what we want,
998 * and if we block until some new event arrives from the
999 * server, other events already in the queue (like Expose)
1000 * will be deferred.
1002 void
1003 WMMaskEvent(Display *dpy, long mask, XEvent *event)
1005 while (!XCheckMaskEvent(dpy, mask, event)) {
1006 /* Do idle stuff while there are no timer or X events */
1007 while (checkIdleHandlers()) {
1008 if (XCheckMaskEvent(dpy, mask, event))
1009 return;
1012 /* Wait for input on the X connection socket */
1013 W_WaitForEvent(dpy, mask);
1015 /* Check any expired timers */
1016 checkTimerHandlers();
1019 #endif
1021 Bool
1022 WMScreenPending(WMScreen *scr)
1024 if (XPending(scr->display))
1025 return True;
1026 else
1027 return False;
1031 WMEventHook*
1032 WMHookEventHandler(WMEventHook *handler)
1034 WMEventHook *oldHandler = extraEventHandler;
1036 extraEventHandler = handler;
1038 return oldHandler;