added responder chain alike stuff for relaying kbd events from widget to widget
[wmaker-crm.git] / WINGs / wevent.c
blob201f3e02cae1f5ffa6dad55b179b93fccfb1b077
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 } 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 != WBNotFound) {
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 != WBNotFound) {
295 wfree(handler);
296 WMDeleteFromBag(inputHandler, pos);
302 static Bool
303 checkIdleHandlers()
305 IdleHandler *handler;
306 WMBag *handlerCopy;
307 WMBagIterator iter;
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 handlerCopy = WMCreateBag(WMGetBagItemCount(idleHandler));
316 WMAppendBag(handlerCopy, idleHandler);
318 for (handler = WMBagFirst(handlerCopy, &iter);
319 iter != NULL;
320 handler = WMBagNext(handlerCopy, &iter)) {
321 /* check if the handler still exist or was removed by a callback */
322 if (WMGetFirstInBag(idleHandler, handler) == WBNotFound)
323 continue;
325 (*handler->callback)(handler->clientData);
326 WMDeleteIdleHandler(handler);
329 WMFreeBag(handlerCopy);
331 W_FlushIdleNotificationQueue();
333 /* this is not necesarrily False, because one handler can re-add itself */
334 return (WMGetBagItemCount(idleHandler)>0);
339 static void
340 checkTimerHandlers()
342 TimerHandler *handler;
343 struct timeval now;
345 if (!timerHandler) {
346 W_FlushASAPNotificationQueue();
347 return;
350 rightNow(&now);
352 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
353 handler = timerHandler;
354 timerHandler = timerHandler->next;
355 handler->next = NULL;
356 (*handler->callback)(handler->clientData);
357 wfree(handler);
360 W_FlushASAPNotificationQueue();
365 static void
366 delayUntilNextTimerEvent(struct timeval *delay)
368 struct timeval now;
370 if (!timerHandler) {
371 /* The return value of this function is only valid if there _are_
372 timers active. */
373 delay->tv_sec = 0;
374 delay->tv_usec = 0;
375 return;
378 rightNow(&now);
379 if (IS_AFTER(now, timerHandler->when)) {
380 delay->tv_sec = 0;
381 delay->tv_usec = 0;
382 } else {
383 delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
384 delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
385 if (delay->tv_usec < 0) {
386 delay->tv_usec += 1000000;
387 delay->tv_sec--;
396 * WMCreateEventHandler--
397 * Create an event handler and put it in the event handler list for the
398 * view. If the same callback and clientdata are already used in another
399 * handler, the masks are swapped.
402 void
403 WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
404 void *clientData)
406 W_EventHandler *handler, *ptr;
407 unsigned long eventMask;
408 WMBagIterator iter;
411 handler = NULL;
412 eventMask = mask;
414 WM_ITERATE_BAG(view->eventHandlers, ptr, iter) {
415 if (ptr->clientData == clientData && ptr->proc == eventProc) {
416 handler = ptr;
417 eventMask |= ptr->eventMask;
420 if (!handler) {
421 handler = wmalloc(sizeof(W_EventHandler));
423 WMPutInBag(view->eventHandlers, handler);
425 /* select events for window */
426 handler->eventMask = eventMask;
427 handler->proc = eventProc;
428 handler->clientData = clientData;
433 * WMDeleteEventHandler--
434 * Delete event handler matching arguments from windows
435 * event handler list.
438 void
439 WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
440 void *clientData)
442 W_EventHandler *handler, *ptr;
443 WMBagIterator iter;
445 handler = NULL;
447 WM_ITERATE_BAG(view->eventHandlers, ptr, iter) {
448 if (ptr->eventMask == mask && ptr->proc == eventProc
449 && ptr->clientData == clientData) {
450 handler = ptr;
451 break;
455 if (!handler)
456 return;
458 WMRemoveFromBag(view->eventHandlers, handler);
460 wfree(handler);
465 void
466 W_CleanUpEvents(WMView *view)
468 W_EventHandler *ptr;
469 WMBagIterator iter;
471 WM_ITERATE_BAG(view->eventHandlers, ptr, iter) {
472 wfree(ptr);
478 static Time
479 getEventTime(WMScreen *screen, XEvent *event)
481 switch (event->type) {
482 case ButtonPress:
483 case ButtonRelease:
484 return event->xbutton.time;
485 case KeyPress:
486 case KeyRelease:
487 return event->xkey.time;
488 case MotionNotify:
489 return event->xmotion.time;
490 case EnterNotify:
491 case LeaveNotify:
492 return event->xcrossing.time;
493 case PropertyNotify:
494 return event->xproperty.time;
495 case SelectionClear:
496 return event->xselectionclear.time;
497 case SelectionRequest:
498 return event->xselectionrequest.time;
499 case SelectionNotify:
500 return event->xselection.time;
501 default:
502 return screen->lastEventTime;
507 void
508 W_CallDestroyHandlers(W_View *view)
510 XEvent event;
511 WMBagIterator iter;
512 W_EventHandler *hPtr;
514 event.type = DestroyNotify;
515 event.xdestroywindow.window = view->window;
516 event.xdestroywindow.event = view->window;
518 WM_ITERATE_BAG(view->eventHandlers, hPtr, iter) {
519 if (hPtr->eventMask & StructureNotifyMask) {
520 (*hPtr->proc)(&event, hPtr->clientData);
527 void
528 WMSetViewNextResponder(WMView *view, WMView *responder)
530 /* set the widget to receive keyboard events that aren't handled
531 * by this widget */
533 view->nextResponder = responder;
537 void
538 WMRelayToNextResponder(WMView *view, XEvent *event)
540 unsigned long mask = eventMasks[event->xany.type];
542 if (view->nextResponder) {
543 WMView *next = view->nextResponder;
544 W_EventHandler *hPtr;
545 WMBagIterator iter;
547 WM_ITERATE_BAG(next->eventHandlers, hPtr, iter) {
548 if ((hPtr->eventMask & mask)) {
549 (*hPtr->proc)(event, hPtr->clientData);
557 WMHandleEvent(XEvent *event)
559 W_EventHandler *hPtr;
560 W_View *view, *vPtr, *toplevel;
561 unsigned long mask;
562 Window window;
563 WMBagIterator iter;
565 if (event->type == MappingNotify) {
566 XRefreshKeyboardMapping(&event->xmapping);
567 return True;
570 mask = eventMasks[event->xany.type];
572 window = event->xany.window;
574 /* diferentiate SubstructureNotify with StructureNotify */
575 if (mask == StructureNotifyMask) {
576 if (event->xmap.event != event->xmap.window) {
577 mask = SubstructureNotifyMask;
578 window = event->xmap.event;
581 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 /* handle selection related events */
597 W_HandleSelectionEvent(event);
599 } else if (event->type == ClientMessage) {
601 W_HandleDNDClientMessage(toplevel, &event->xclient);
604 /* if it's a key event, redispatch it to the focused control */
605 if (mask & (KeyPressMask|KeyReleaseMask)) {
606 W_View *focused = W_FocusedViewOfToplevel(toplevel);
608 if (focused) {
609 view = focused;
613 /* compress Motion events */
614 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
615 while (XPending(event->xmotion.display)) {
616 XEvent ev;
617 XPeekEvent(event->xmotion.display, &ev);
618 if (ev.type == MotionNotify
619 && event->xmotion.window == ev.xmotion.window
620 && event->xmotion.subwindow == ev.xmotion.subwindow) {
621 /* replace events */
622 XNextEvent(event->xmotion.display, event);
623 } else break;
627 /* compress expose events */
628 if (event->type == Expose && !view->flags.dontCompressExpose) {
629 while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
630 Expose, event));
634 if (view->screen->modalLoop && toplevel!=view->screen->modalView
635 && !toplevel->flags.worksWhenModal) {
636 if (event->type == KeyPress || event->type == KeyRelease
637 || event->type == MotionNotify || event->type == ButtonPress
638 || event->type == ButtonRelease
639 || event->type == FocusIn || event->type == FocusOut) {
640 return True;
644 /* do balloon stuffs */
645 if (event->type == EnterNotify)
646 W_BalloonHandleEnterView(view);
647 else if (event->type == LeaveNotify)
648 W_BalloonHandleLeaveView(view);
650 /* This is a hack. It will make the panel be secure while
651 * the event handlers are handled, as some event handler
652 * might destroy the widget. */
653 W_RetainView(toplevel);
655 WM_ITERATE_BAG(view->eventHandlers, hPtr, iter) {
656 if ((hPtr->eventMask & mask)) {
657 (*hPtr->proc)(event, hPtr->clientData);
660 #if 0
661 /* pass the event to the top level window of the widget */
662 /* TODO: change this to a responder chain */
663 if (view->parent != NULL) {
664 vPtr = view;
665 while (vPtr->parent != NULL)
666 vPtr = vPtr->parent;
668 WM_ITERATE_BAG(vPtr->eventHandlers, hPtr, iter) {
669 if (hPtr->eventMask & mask) {
670 (*hPtr->proc)(event, hPtr->clientData);
674 #endif
675 /* save button click info to track double-clicks */
676 if (view->screen->ignoreNextDoubleClick) {
677 view->screen->ignoreNextDoubleClick = 0;
678 } else {
679 if (event->type == ButtonPress) {
680 view->screen->lastClickWindow = event->xbutton.window;
681 view->screen->lastClickTime = event->xbutton.time;
685 W_ReleaseView(toplevel);
687 return True;
692 WMIsDoubleClick(XEvent *event)
694 W_View *view;
696 if (event->type != ButtonPress)
697 return False;
699 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
701 if (!view)
702 return False;
704 if (view->screen->lastClickWindow != event->xbutton.window)
705 return False;
707 if (event->xbutton.time - view->screen->lastClickTime
708 < WINGsConfiguration.doubleClickDelay) {
709 view->screen->lastClickTime = 0;
710 view->screen->lastClickWindow = None;
711 view->screen->ignoreNextDoubleClick = 1;
712 return True;
713 } else
714 return False;
718 Bool
719 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
721 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
722 struct pollfd *fds;
723 InputHandler *handler;
724 int count, timeout, nfds, i, retval;
726 if (inputHandler)
727 nfds = WMGetBagItemCount(inputHandler);
728 else
729 nfds = 0;
731 fds = wmalloc(nfds+1 * sizeof(struct pollfd));
732 /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
733 fds[nfds].fd = ConnectionNumber(dpy);
734 fds[nfds].events = POLLIN;
736 for (i = 0; i<nfds; i++) {
737 handler = WMGetFromBag(inputHandler, i);
738 fds[i].fd = handler->fd;
739 fds[i].events = 0;
740 if (handler->mask & WIReadMask)
741 fds[i].events |= POLLIN;
743 if (handler->mask & WIWriteMask)
744 fds[i].events |= POLLOUT;
746 #if 0 /* FIXME */
747 if (handler->mask & WIExceptMask)
748 FD_SET(handler->fd, &eset);
749 #endif
753 * Setup the select() timeout to the estimated time until the
754 * next timer expires.
756 if (timerPending()) {
757 struct timeval tv;
758 delayUntilNextTimerEvent(&tv);
759 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
760 } else {
761 timeout = -1;
764 if (xeventmask==0) {
765 if (XPending(dpy))
766 return True;
767 } else {
768 XEvent ev;
769 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
770 XPutBackEvent(dpy, &ev);
771 return True;
775 count = poll(fds, nfds, timeout);
777 if (count>0 && nfds>0) {
778 WMBag *handlerCopy = WMCreateBag(nfds);
780 for (i=0; i<nfds; i++)
781 WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
783 for (i=0; i<nfds; i++) {
784 int mask;
786 handler = WMGetFromBag(handlerCopy, i);
787 /* check if the handler still exist or was removed by a callback */
788 if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
789 continue;
791 mask = 0;
793 if ((handler->mask & WIReadMask) &&
794 (fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
795 mask |= WIReadMask;
797 if ((handler->mask & WIWriteMask) &&
798 (fds[i].revents & (POLLOUT | POLLWRBAND)))
799 mask |= WIWriteMask;
801 if ((handler->mask & WIExceptMask) &&
802 (fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
803 mask |= WIExceptMask;
805 if (mask!=0 && handler->callback) {
806 (*handler->callback)(handler->fd, mask,
807 handler->clientData);
811 WMFreeBag(handlerCopy);
814 retval = fds[nfds].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
815 wfree(fds);
817 W_FlushASAPNotificationQueue();
819 return retval;
820 #else /* not HAVE_POLL */
821 #ifdef HAVE_SELECT
822 struct timeval timeout;
823 struct timeval *timeoutPtr;
824 fd_set rset, wset, eset;
825 int maxfd, nfds, i;
826 int count;
827 InputHandler *handler;
829 FD_ZERO(&rset);
830 FD_ZERO(&wset);
831 FD_ZERO(&eset);
833 FD_SET(ConnectionNumber(dpy), &rset);
834 maxfd = ConnectionNumber(dpy);
836 if (inputHandler)
837 nfds = WMGetBagItemCount(inputHandler);
838 else
839 nfds = 0;
841 for (i=0; i<nfds; i++) {
842 handler = WMGetFromBag(inputHandler, i);
843 if (handler->mask & WIReadMask)
844 FD_SET(handler->fd, &rset);
846 if (handler->mask & WIWriteMask)
847 FD_SET(handler->fd, &wset);
849 if (handler->mask & WIExceptMask)
850 FD_SET(handler->fd, &eset);
852 if (maxfd < handler->fd)
853 maxfd = handler->fd;
858 * Setup the select() timeout to the estimated time until the
859 * next timer expires.
861 if (timerPending()) {
862 delayUntilNextTimerEvent(&timeout);
863 timeoutPtr = &timeout;
864 } else {
865 timeoutPtr = (struct timeval*)0;
868 XSync(dpy, False);
869 if (xeventmask==0) {
870 if (XPending(dpy))
871 return True;
872 } else {
873 XEvent ev;
874 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
875 XPutBackEvent(dpy, &ev);
876 return True;
880 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
882 if (count>0 && nfds>0) {
883 WMBag *handlerCopy = WMCreateBag(nfds);
885 for (i=0; i<nfds; i++)
886 WMPutInBag(handlerCopy, WMGetFromBag(inputHandler, i));
888 for (i=0; i<nfds; i++) {
889 int mask;
891 handler = WMGetFromBag(handlerCopy, i);
892 /* check if the handler still exist or was removed by a callback */
893 if (WMGetFirstInBag(inputHandler, handler) == WBNotFound)
894 continue;
896 mask = 0;
898 if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
899 mask |= WIReadMask;
901 if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
902 mask |= WIWriteMask;
904 if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
905 mask |= WIExceptMask;
907 if (mask!=0 && handler->callback) {
908 (*handler->callback)(handler->fd, mask,
909 handler->clientData);
913 WMFreeBag(handlerCopy);
916 W_FlushASAPNotificationQueue();
918 return FD_ISSET(ConnectionNumber(dpy), &rset);
919 #else /* not HAVE_SELECT, not HAVE_POLL */
920 Neither select nor poll. You lose.
921 #endif /* HAVE_SELECT */
922 #endif /* HAVE_POLL */
926 void
927 WMNextEvent(Display *dpy, XEvent *event)
929 /* Check any expired timers */
930 checkTimerHandlers();
932 while (XPending(dpy) == 0) {
933 /* Do idle stuff */
934 /* Do idle and timer stuff while there are no timer or X events */
935 while (!XPending(dpy) && checkIdleHandlers()) {
936 /* dispatch timer events */
937 checkTimerHandlers();
941 * Make sure that new events did not arrive while we were doing
942 * timer/idle stuff. Or we might block forever waiting for
943 * an event that already arrived.
945 /* wait to something happen */
946 W_WaitForEvent(dpy, 0);
948 /* Check any expired timers */
949 checkTimerHandlers();
952 XNextEvent(dpy, event);
955 #if 0
956 void
957 WMMaskEvent(Display *dpy, long mask, XEvent *event)
959 unsigned long milliseconds;
960 struct timeval timeout;
961 struct timeval *timeoutOrInfty;
962 fd_set readset;
964 while (!XCheckMaskEvent(dpy, mask, event)) {
965 /* Do idle stuff while there are no timer or X events */
966 while (checkIdleHandlers()) {
967 if (XCheckMaskEvent(dpy, mask, event))
968 return;
972 * Setup the select() timeout to the estimated time until the
973 * next timer expires.
975 if (timerPending()) {
976 delayUntilNextTimerEvent(&timeout);
977 timeoutOrInfty = &timeout;
978 } else {
979 timeoutOrInfty = (struct timeval*)0;
982 if (XCheckMaskEvent(dpy, mask, event))
983 return;
985 /* Wait for input on the X connection socket */
986 FD_ZERO(&readset);
987 FD_SET(ConnectionNumber(dpy), &readset);
988 select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
989 timeoutOrInfty);
991 /* Check any expired timers */
992 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()) {
1010 if (XCheckMaskEvent(dpy, mask, event))
1011 return;
1014 /* Wait for input on the X connection socket */
1015 W_WaitForEvent(dpy, mask);
1017 /* Check any expired timers */
1018 checkTimerHandlers();
1021 #endif
1023 Bool
1024 WMScreenPending(WMScreen *scr)
1026 if (XPending(scr->display))
1027 return True;
1028 else
1029 return False;
1033 WMEventHook*
1034 WMHookEventHandler(WMEventHook *handler)
1036 WMEventHook *oldHandler = extraEventHandler;
1038 extraEventHandler = handler;
1040 return oldHandler;