Code update for Window Maker version 0.50.0
[wmaker-crm.git] / WINGs / wevent.c
blob2be11367b84f6a3c9e38c2d01a9c7eac12c10558
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 #ifdef HAVE_SYS_SELECT_H
20 # include <sys/select.h>
21 #endif
23 #ifdef HAVE_GETTIMEOFDAY
24 # include <sys/time.h>
25 # ifdef TIME_WITH_SYS_TIME
26 # include <time.h>
27 # endif
28 #else /* ! HAVE_GETTIMEOFDAY */
29 # include <time.h>
30 #endif /* ! HAVE_GETTIMEOFDAY */
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 #ifdef HAVE_GETTIMEOFDAY
123 static void
124 rightNow(struct timeval *tv) {
125 gettimeofday(tv, NULL);
127 #else /* !HAVE_GETTIMEOFDAY */
128 # define rightNow(tv) (tv)->tv_sec==time(NULL),(tv)->tv_usec=0
129 #endif /* !HAVE_GETTIMEOFDAY */
132 /* is t1 after t2 ? */
133 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
134 (((t1).tv_sec == (t2).tv_sec) \
135 && ((t1).tv_usec > (t2).tv_usec)))
138 static void
139 addmillisecs(struct timeval *tv, int milliseconds)
141 tv->tv_usec += milliseconds*1000;
143 tv->tv_sec += tv->tv_usec/1000000;
144 tv->tv_usec = tv->tv_usec%1000000;
148 WMHandlerID
149 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
151 TimerHandler *handler, *tmp;
153 handler = malloc(sizeof(TimerHandler));
154 if (!handler)
155 return NULL;
157 rightNow(&handler->when);
158 addmillisecs(&handler->when, milliseconds);
159 handler->callback = callback;
160 handler->clientData = cdata;
161 /* insert callback in queue, sorted by time left */
162 if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
163 /* first in the queue */
164 handler->next = timerHandler;
165 timerHandler = handler;
166 } else {
167 tmp = timerHandler;
168 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
169 tmp = tmp->next;
171 handler->next = tmp->next;
172 tmp->next = handler;
174 return handler;
179 void
180 WMDeleteTimerWithClientData(void *cdata)
182 TimerHandler *handler, *tmp;
184 if (!cdata || !timerHandler)
185 return;
187 tmp = timerHandler;
188 if (tmp->clientData==cdata) {
189 timerHandler = tmp->next;
190 free(tmp);
191 } else {
192 while (tmp->next) {
193 if (tmp->next->clientData==cdata) {
194 handler = tmp->next;
195 tmp->next = handler->next;
196 free(handler);
197 break;
199 tmp = tmp->next;
206 void
207 WMDeleteTimerHandler(WMHandlerID handlerID)
209 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
211 if (!handler || !timerHandler)
212 return;
214 tmp = timerHandler;
215 if (tmp==handler) {
216 timerHandler = handler->next;
217 free(handler);
218 } else {
219 while (tmp->next) {
220 if (tmp->next==handler) {
221 tmp->next=handler->next;
222 free(handler);
223 break;
225 tmp = tmp->next;
232 WMHandlerID
233 WMAddIdleHandler(WMCallback *callback, void *cdata)
235 IdleHandler *handler, *tmp;
237 handler = malloc(sizeof(IdleHandler));
238 if (!handler)
239 return NULL;
241 handler->callback = callback;
242 handler->clientData = cdata;
243 handler->next = NULL;
244 /* add callback at end of queue */
245 if (!idleHandler) {
246 idleHandler = handler;
247 } else {
248 tmp = idleHandler;
249 while (tmp->next) {
250 tmp = tmp->next;
252 tmp->next = handler;
255 return handler;
260 void
261 WMDeleteIdleHandler(WMHandlerID handlerID)
263 IdleHandler *tmp, *handler = (IdleHandler*)handlerID;
265 if (!handler || !idleHandler)
266 return;
268 tmp = idleHandler;
269 if (tmp == handler) {
270 idleHandler = handler->next;
271 free(handler);
272 } else {
273 while (tmp->next) {
274 if (tmp->next == handler) {
275 tmp->next = handler->next;
276 free(handler);
277 break;
279 tmp = tmp->next;
286 WMHandlerID
287 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
289 InputHandler *handler;
291 handler = wmalloc(sizeof(InputHandler));
293 handler->fd = fd;
294 handler->mask = condition;
295 handler->callback = proc;
296 handler->clientData = clientData;
298 handler->next = inputHandler;
300 inputHandler = handler;
302 return handler;
306 void
307 WMDeleteInputHandler(WMHandlerID handlerID)
309 InputHandler *tmp, *handler = (InputHandler*)handlerID;
311 if (!handler || !inputHandler)
312 return;
314 tmp = inputHandler;
315 if (tmp == handler) {
316 inputHandler = handler->next;
317 free(handler);
318 } else {
319 while (tmp->next) {
320 if (tmp->next == handler) {
321 tmp->next = handler->next;
322 free(handler);
323 break;
325 tmp = tmp->next;
331 static void
332 checkIdleHandlers()
334 IdleHandler *handler, *tmp;
336 if (!idleHandler)
337 return;
339 handler = idleHandler;
341 /* we will process all idleHandlers so, empty the handler list */
342 idleHandler = NULL;
344 while (handler) {
345 tmp = handler->next;
346 (*handler->callback)(handler->clientData);
347 /* remove the handler */
348 free(handler);
350 handler = tmp;
356 static void
357 checkTimerHandlers()
359 TimerHandler *handler;
360 struct timeval now;
362 rightNow(&now);
364 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
365 handler = timerHandler;
366 timerHandler = timerHandler->next;
367 handler->next = NULL;
368 (*handler->callback)(handler->clientData);
369 free(handler);
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 it's a key event, redispatch it to the focused control */
595 if (mask & (KeyPressMask|KeyReleaseMask)) {
596 W_View *focused = W_FocusedViewOfToplevel(toplevel);
598 if (focused) {
599 view = focused;
603 /* compress Motion events */
604 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
605 while (XPending(event->xmotion.display)) {
606 XEvent ev;
607 XPeekEvent(event->xmotion.display, &ev);
608 if (ev.type == MotionNotify
609 && event->xmotion.window == ev.xmotion.window
610 && event->xmotion.subwindow == ev.xmotion.subwindow) {
611 /* replace events */
612 XNextEvent(event->xmotion.display, event);
613 } else break;
617 /* compress expose events */
618 if (event->type == Expose && !view->flags.dontCompressExpose) {
619 while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
620 Expose, event));
624 if (view->screen->modal && toplevel!=view->screen->modalView
625 && !toplevel->flags.worksWhenModal) {
626 if (event->type == KeyPress || event->type == KeyRelease
627 || event->type == MotionNotify || event->type == ButtonPress
628 || event->type == ButtonRelease
629 || event->type == FocusIn || event->type == FocusOut) {
630 return True;
634 /* This is a hack. It will make the panel be secure while
635 * the event handlers are handled, as some event handler
636 * might destroy the widget. */
637 W_RetainView(toplevel);
639 hPtr = view->handlerList;
641 while (hPtr!=NULL) {
642 W_EventHandler *tmp;
644 tmp = hPtr->nextHandler;
646 if ((hPtr->eventMask & mask)) {
647 (*hPtr->proc)(event, hPtr->clientData);
650 hPtr = tmp;
653 /* pass the event to the top level window of the widget */
654 if (view->parent!=NULL) {
655 vPtr = view;
656 while (vPtr->parent!=NULL)
657 vPtr = vPtr->parent;
659 hPtr = vPtr->handlerList;
661 while (hPtr!=NULL) {
663 if (hPtr->eventMask & mask) {
664 (*hPtr->proc)(event, hPtr->clientData);
666 hPtr = hPtr->nextHandler;
670 /* save button click info to track double-clicks */
671 if (view->screen->ignoreNextDoubleClick) {
672 view->screen->ignoreNextDoubleClick = 0;
673 } else {
674 if (event->type == ButtonPress) {
675 view->screen->lastClickWindow = event->xbutton.window;
676 view->screen->lastClickTime = event->xbutton.time;
680 W_ReleaseView(toplevel);
682 return True;
687 WMIsDoubleClick(XEvent *event)
689 W_View *view;
691 if (event->type != ButtonPress)
692 return False;
694 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
696 if (!view)
697 return False;
699 if (view->screen->lastClickWindow != event->xbutton.window)
700 return False;
702 if (event->xbutton.time - view->screen->lastClickTime
703 < WINGsConfiguration.doubleClickDelay) {
704 view->screen->lastClickTime = 0;
705 view->screen->lastClickWindow = None;
706 view->screen->ignoreNextDoubleClick = 1;
707 return True;
708 } else
709 return False;
713 Bool
714 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
716 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
717 struct pollfd *fds;
718 InputHandler *handler;
719 int count, timeout, nfds, k, retval;
721 for (nfds = 1, handler = inputHandler;
722 handler != 0; handler = handler->next) nfds++;
724 fds = wmalloc(nfds * sizeof(struct pollfd));
725 fds[0].fd = ConnectionNumber(dpy);
726 fds[0].events = POLLIN;
728 for (k = 1, handler = inputHandler;
729 handler;
730 handler = handler->next, k++) {
731 fds[k].fd = handler->fd;
732 fds[k].events = 0;
733 if (handler->mask & WIReadMask)
734 fds[k].events |= POLLIN;
736 if (handler->mask & WIWriteMask)
737 fds[k].events |= POLLOUT;
739 #if 0 /* FIXME */
740 if (handler->mask & WIExceptMask)
741 FD_SET(handler->fd, &eset);
742 #endif
746 * Setup the select() timeout to the estimated time until the
747 * next timer expires.
749 if (timerPending()) {
750 struct timeval tv;
751 delayUntilNextTimerEvent(&tv);
752 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
753 } else {
754 timeout = -1;
757 if (xeventmask==0) {
758 if (XPending(dpy))
759 return True;
760 } else {
761 XEvent ev;
762 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
763 XPutBackEvent(dpy, &ev);
764 return True;
768 count = poll(fds, nfds, timeout);
770 if (count > 0) {
771 handler = inputHandler;
772 k = 1;
773 while (handler) {
774 int mask;
776 mask = 0;
778 if (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI))
779 mask |= WIReadMask;
781 if (fds[k].revents & (POLLOUT | POLLWRBAND))
782 mask |= WIWriteMask;
784 if (fds[k].revents & (POLLHUP | POLLNVAL | POLLERR))
785 mask |= WIExceptMask;
787 if (mask!=0 && handler->callback) {
788 (*handler->callback)(handler->fd, mask,
789 handler->clientData);
792 handler = handler->next;
793 k++;
797 retval = fds[0].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
798 free(fds);
800 return retval;
801 #else /* not HAVE_POLL */
802 #ifdef HAVE_SELECT
803 struct timeval timeout;
804 struct timeval *timeoutPtr;
805 fd_set rset, wset, eset;
806 int maxfd;
807 int count;
808 InputHandler *handler = inputHandler;
810 FD_ZERO(&rset);
811 FD_ZERO(&wset);
812 FD_ZERO(&eset);
814 FD_SET(ConnectionNumber(dpy), &rset);
815 maxfd = ConnectionNumber(dpy);
817 while (handler) {
818 if (handler->mask & WIReadMask)
819 FD_SET(handler->fd, &rset);
821 if (handler->mask & WIWriteMask)
822 FD_SET(handler->fd, &wset);
824 if (handler->mask & WIExceptMask)
825 FD_SET(handler->fd, &eset);
827 if (maxfd < handler->fd)
828 maxfd = handler->fd;
830 handler = handler->next;
835 * Setup the select() timeout to the estimated time until the
836 * next timer expires.
838 if (timerPending()) {
839 delayUntilNextTimerEvent(&timeout);
840 timeoutPtr = &timeout;
841 } else {
842 timeoutPtr = (struct timeval*)0;
845 XSync(dpy, False);
846 if (xeventmask==0) {
847 if (XPending(dpy))
848 return True;
849 } else {
850 XEvent ev;
851 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
852 XPutBackEvent(dpy, &ev);
853 return True;
857 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
859 if (count > 0) {
860 handler = inputHandler;
862 while (handler) {
863 int mask;
865 mask = 0;
867 if (FD_ISSET(handler->fd, &rset))
868 mask |= WIReadMask;
870 if (FD_ISSET(handler->fd, &wset))
871 mask |= WIWriteMask;
873 if (FD_ISSET(handler->fd, &eset))
874 mask |= WIExceptMask;
876 if (mask!=0 && handler->callback) {
877 (*handler->callback)(handler->fd, mask,
878 handler->clientData);
881 handler = handler->next;
885 return FD_ISSET(ConnectionNumber(dpy), &rset);
886 #else /* not HAVE_SELECT, not HAVE_POLL */
887 Neither select nor poll. You lose.
888 #endif /* HAVE_SELECT */
889 #endif /* HAVE_POLL */
892 void
893 WMNextEvent(Display *dpy, XEvent *event)
895 /* Check any expired timers */
896 if (timerPending()) {
897 checkTimerHandlers();
900 while (XPending(dpy) == 0) {
901 /* Do idle stuff */
902 /* Do idle and timer stuff while there are no timer or X events */
903 while (!XPending(dpy) && idlePending()) {
904 if (idlePending())
905 checkIdleHandlers();
906 /* dispatch timer events */
907 if (timerPending())
908 checkTimerHandlers();
912 * Make sure that new events did not arrive while we were doing
913 * timer/idle stuff. Or we might block forever waiting for
914 * an event that already arrived.
916 /* wait to something happen */
917 W_WaitForEvent(dpy, 0);
919 /* Check any expired timers */
920 if (timerPending()) {
921 checkTimerHandlers();
925 XNextEvent(dpy, event);
928 #if 0
929 void
930 WMMaskEvent(Display *dpy, long mask, XEvent *event)
932 unsigned long milliseconds;
933 struct timeval timeout;
934 struct timeval *timeoutOrInfty;
935 fd_set readset;
937 while (!XCheckMaskEvent(dpy, mask, event)) {
938 /* Do idle stuff while there are no timer or X events */
939 while (idlePending()) {
940 checkIdleHandlers();
941 if (XCheckMaskEvent(dpy, mask, event))
942 return;
946 * Setup the select() timeout to the estimated time until the
947 * next timer expires.
949 if (timerPending()) {
950 delayUntilNextTimerEvent(&timeout);
951 timeoutOrInfty = &timeout;
952 } else {
953 timeoutOrInfty = (struct timeval*)0;
956 if (XCheckMaskEvent(dpy, mask, event))
957 return;
959 /* Wait for input on the X connection socket */
960 FD_ZERO(&readset);
961 FD_SET(ConnectionNumber(dpy), &readset);
962 select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
963 timeoutOrInfty);
965 /* Check any expired timers */
966 if (timerPending()) {
967 checkTimerHandlers();
971 #endif
972 #if 1
974 * Cant use this because XPending() will make W_WaitForEvent
975 * return even if the event in the queue is not what we want,
976 * and if we block until some new event arrives from the
977 * server, other events already in the queue (like Expose)
978 * will be deferred.
980 void
981 WMMaskEvent(Display *dpy, long mask, XEvent *event)
983 while (!XCheckMaskEvent(dpy, mask, event)) {
984 /* Do idle stuff while there are no timer or X events */
985 while (idlePending()) {
986 checkIdleHandlers();
987 if (XCheckMaskEvent(dpy, mask, event))
988 return;
991 /* Wait for input on the X connection socket */
992 W_WaitForEvent(dpy, mask);
994 /* Check any expired timers */
995 if (timerPending()) {
996 checkTimerHandlers();
1000 #endif
1002 Bool
1003 WMScreenPending(WMScreen *scr)
1005 if (XPending(scr->display))
1006 return True;
1007 else
1008 return False;
1012 WMEventHook*
1013 WMHookEventHandler(WMEventHook *handler)
1015 WMEventHook *oldHandler = extraEventHandler;
1017 extraEventHandler = handler;
1019 return oldHandler;