replaced free() with wfree() everywhere
[wmaker-crm.git] / WINGs / wevent.c
blob6016d2704b46583e991a96f78784b40d266cce43
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)
118 #define idlePending() (idleHandler)
121 static void
122 rightNow(struct timeval *tv) {
123 X_GETTIMEOFDAY(tv);
126 /* is t1 after t2 ? */
127 #define IS_AFTER(t1, t2) (((t1).tv_sec > (t2).tv_sec) || \
128 (((t1).tv_sec == (t2).tv_sec) \
129 && ((t1).tv_usec > (t2).tv_usec)))
132 static void
133 addmillisecs(struct timeval *tv, int milliseconds)
135 tv->tv_usec += milliseconds*1000;
137 tv->tv_sec += tv->tv_usec/1000000;
138 tv->tv_usec = tv->tv_usec%1000000;
142 WMHandlerID
143 WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
145 TimerHandler *handler, *tmp;
147 handler = malloc(sizeof(TimerHandler));
148 if (!handler)
149 return NULL;
151 rightNow(&handler->when);
152 addmillisecs(&handler->when, milliseconds);
153 handler->callback = callback;
154 handler->clientData = cdata;
155 /* insert callback in queue, sorted by time left */
156 if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
157 /* first in the queue */
158 handler->next = timerHandler;
159 timerHandler = handler;
160 } else {
161 tmp = timerHandler;
162 while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
163 tmp = tmp->next;
165 handler->next = tmp->next;
166 tmp->next = handler;
168 return handler;
173 void
174 WMDeleteTimerWithClientData(void *cdata)
176 TimerHandler *handler, *tmp;
178 if (!cdata || !timerHandler)
179 return;
181 tmp = timerHandler;
182 if (tmp->clientData==cdata) {
183 timerHandler = tmp->next;
184 wfree(tmp);
185 } else {
186 while (tmp->next) {
187 if (tmp->next->clientData==cdata) {
188 handler = tmp->next;
189 tmp->next = handler->next;
190 wfree(handler);
191 break;
193 tmp = tmp->next;
200 void
201 WMDeleteTimerHandler(WMHandlerID handlerID)
203 TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
205 if (!handler || !timerHandler)
206 return;
208 tmp = timerHandler;
209 if (tmp==handler) {
210 timerHandler = handler->next;
211 wfree(handler);
212 } else {
213 while (tmp->next) {
214 if (tmp->next==handler) {
215 tmp->next=handler->next;
216 wfree(handler);
217 break;
219 tmp = tmp->next;
226 WMHandlerID
227 WMAddIdleHandler(WMCallback *callback, void *cdata)
229 IdleHandler *handler, *tmp;
231 handler = malloc(sizeof(IdleHandler));
232 if (!handler)
233 return NULL;
235 handler->callback = callback;
236 handler->clientData = cdata;
237 handler->next = NULL;
238 /* add callback at end of queue */
239 if (!idleHandler) {
240 idleHandler = handler;
241 } else {
242 tmp = idleHandler;
243 while (tmp->next) {
244 tmp = tmp->next;
246 tmp->next = handler;
249 return handler;
254 void
255 WMDeleteIdleHandler(WMHandlerID handlerID)
257 IdleHandler *tmp, *handler = (IdleHandler*)handlerID;
259 if (!handler || !idleHandler)
260 return;
262 tmp = idleHandler;
263 if (tmp == handler) {
264 idleHandler = handler->next;
265 wfree(handler);
266 } else {
267 while (tmp->next) {
268 if (tmp->next == handler) {
269 tmp->next = handler->next;
270 wfree(handler);
271 break;
273 tmp = tmp->next;
280 WMHandlerID
281 WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
283 InputHandler *handler;
285 handler = wmalloc(sizeof(InputHandler));
287 handler->fd = fd;
288 handler->mask = condition;
289 handler->callback = proc;
290 handler->clientData = clientData;
292 handler->next = inputHandler;
294 inputHandler = handler;
296 return handler;
300 void
301 WMDeleteInputHandler(WMHandlerID handlerID)
303 InputHandler *tmp, *handler = (InputHandler*)handlerID;
305 if (!handler || !inputHandler)
306 return;
308 tmp = inputHandler;
309 if (tmp == handler) {
310 inputHandler = handler->next;
311 wfree(handler);
312 } else {
313 while (tmp->next) {
314 if (tmp->next == handler) {
315 tmp->next = handler->next;
316 wfree(handler);
317 break;
319 tmp = tmp->next;
325 static void
326 checkIdleHandlers()
328 IdleHandler *handler, *tmp;
330 if (!idleHandler) {
331 W_FlushIdleNotificationQueue();
332 return;
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;
348 W_FlushIdleNotificationQueue();
353 static void
354 checkTimerHandlers()
356 TimerHandler *handler;
357 struct timeval now;
359 rightNow(&now);
361 while (timerHandler && IS_AFTER(now, timerHandler->when)) {
362 handler = timerHandler;
363 timerHandler = timerHandler->next;
364 handler->next = NULL;
365 (*handler->callback)(handler->clientData);
366 wfree(handler);
369 W_FlushASAPNotificationQueue();
374 static void
375 delayUntilNextTimerEvent(struct timeval *delay)
377 struct timeval now;
379 if (!timerHandler) {
380 /* The return value of this function is only valid if there _are_
381 timers active. */
382 delay->tv_sec = 0;
383 delay->tv_usec = 0;
384 return;
387 rightNow(&now);
388 if (IS_AFTER(now, timerHandler->when)) {
389 delay->tv_sec = 0;
390 delay->tv_usec = 0;
391 } else {
392 delay->tv_sec = timerHandler->when.tv_sec - now.tv_sec;
393 delay->tv_usec = timerHandler->when.tv_usec - now.tv_usec;
394 if (delay->tv_usec < 0) {
395 delay->tv_usec += 1000000;
396 delay->tv_sec--;
405 * WMCreateEventHandler--
406 * Create an event handler and put it in the event handler list for the
407 * view. If the same callback and clientdata are already used in another
408 * handler, the masks are swapped.
411 void
412 WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
413 void *clientData)
415 W_EventHandler *handler;
416 W_EventHandler *ptr = view->handlerList;
417 unsigned long eventMask;
419 if (ptr==NULL) {
420 handler = wmalloc(sizeof(W_EventHandler));
422 handler->nextHandler = NULL;
424 view->handlerList = handler;
426 eventMask = mask;
427 } else {
428 handler = NULL;
429 eventMask = mask;
430 while (ptr != NULL) {
431 if (ptr->clientData == clientData && ptr->proc == eventProc) {
432 handler = ptr;
434 eventMask |= ptr->eventMask;
436 ptr = ptr->nextHandler;
438 if (!handler) {
439 handler = wmalloc(sizeof(W_EventHandler));
440 handler->nextHandler = view->handlerList;
441 view->handlerList = handler;
445 /* select events for window */
446 handler->eventMask = mask;
447 handler->proc = eventProc;
448 handler->clientData = clientData;
453 * WMDeleteEventHandler--
454 * Delete event handler matching arguments from windows
455 * event handler list.
458 void
459 WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
460 void *clientData)
462 W_EventHandler *handler, *ptr, *pptr;
464 ptr = view->handlerList;
466 handler = NULL;
467 pptr = NULL;
469 while (ptr!=NULL) {
470 if (ptr->eventMask == mask && ptr->proc == eventProc
471 && ptr->clientData == clientData) {
472 handler = ptr;
473 break;
475 pptr = ptr;
476 ptr = ptr->nextHandler;
479 if (!handler)
480 return;
482 if (!pptr) {
483 view->handlerList = handler->nextHandler;
484 } else {
485 pptr->nextHandler = handler->nextHandler;
487 wfree(handler);
492 void
493 W_CleanUpEvents(WMView *view)
495 W_EventHandler *ptr, *nptr;
497 ptr = view->handlerList;
499 while (ptr!=NULL) {
500 nptr = ptr->nextHandler;
501 wfree(ptr);
502 ptr = nptr;
508 static Time
509 getEventTime(WMScreen *screen, XEvent *event)
511 switch (event->type) {
512 case ButtonPress:
513 case ButtonRelease:
514 return event->xbutton.time;
515 case KeyPress:
516 case KeyRelease:
517 return event->xkey.time;
518 case MotionNotify:
519 return event->xmotion.time;
520 case EnterNotify:
521 case LeaveNotify:
522 return event->xcrossing.time;
523 case PropertyNotify:
524 return event->xproperty.time;
525 case SelectionClear:
526 return event->xselectionclear.time;
527 case SelectionRequest:
528 return event->xselectionrequest.time;
529 case SelectionNotify:
530 return event->xselection.time;
531 default:
532 return screen->lastEventTime;
537 void
538 W_CallDestroyHandlers(W_View *view)
540 XEvent event;
541 W_EventHandler *hPtr;
543 event.type = DestroyNotify;
544 event.xdestroywindow.window = view->window;
545 event.xdestroywindow.event = view->window;
546 hPtr = view->handlerList;
547 while (hPtr!=NULL) {
548 if (hPtr->eventMask & StructureNotifyMask) {
549 (*hPtr->proc)(&event, hPtr->clientData);
552 hPtr = hPtr->nextHandler;
558 WMHandleEvent(XEvent *event)
560 W_EventHandler *hPtr;
561 W_View *view, *vPtr, *toplevel;
562 unsigned long mask;
563 Window window;
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);
582 if (!view) {
583 if (extraEventHandler)
584 (extraEventHandler)(event);
586 return False;
589 view->screen->lastEventTime = getEventTime(view->screen, event);
591 toplevel = W_TopLevelOfView(view);
593 if (event->type == SelectionNotify || event->type == SelectionClear
594 || event->type == SelectionRequest) {
595 /* handle selection related events */
596 W_HandleSelectionEvent(event);
599 /* if it's a key event, redispatch it to the focused control */
600 if (mask & (KeyPressMask|KeyReleaseMask)) {
601 W_View *focused = W_FocusedViewOfToplevel(toplevel);
603 if (focused) {
604 view = focused;
608 /* compress Motion events */
609 if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
610 while (XPending(event->xmotion.display)) {
611 XEvent ev;
612 XPeekEvent(event->xmotion.display, &ev);
613 if (ev.type == MotionNotify
614 && event->xmotion.window == ev.xmotion.window
615 && event->xmotion.subwindow == ev.xmotion.subwindow) {
616 /* replace events */
617 XNextEvent(event->xmotion.display, event);
618 } else break;
622 /* compress expose events */
623 if (event->type == Expose && !view->flags.dontCompressExpose) {
624 while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
625 Expose, event));
629 if (view->screen->modal && toplevel!=view->screen->modalView
630 && !toplevel->flags.worksWhenModal) {
631 if (event->type == KeyPress || event->type == KeyRelease
632 || event->type == MotionNotify || event->type == ButtonPress
633 || event->type == ButtonRelease
634 || event->type == FocusIn || event->type == FocusOut) {
635 return True;
639 /* do balloon stuffs */
640 if (event->type == EnterNotify)
641 W_BalloonHandleEnterView(view);
642 else if (event->type == LeaveNotify)
643 W_BalloonHandleLeaveView(view);
645 /* This is a hack. It will make the panel be secure while
646 * the event handlers are handled, as some event handler
647 * might destroy the widget. */
648 W_RetainView(toplevel);
650 hPtr = view->handlerList;
652 while (hPtr!=NULL) {
653 W_EventHandler *tmp;
655 tmp = hPtr->nextHandler;
657 if ((hPtr->eventMask & mask)) {
658 (*hPtr->proc)(event, hPtr->clientData);
661 hPtr = tmp;
664 /* pass the event to the top level window of the widget */
665 if (view->parent!=NULL) {
666 vPtr = view;
667 while (vPtr->parent!=NULL)
668 vPtr = vPtr->parent;
670 hPtr = vPtr->handlerList;
672 while (hPtr!=NULL) {
674 if (hPtr->eventMask & mask) {
675 (*hPtr->proc)(event, hPtr->clientData);
677 hPtr = hPtr->nextHandler;
681 /* save button click info to track double-clicks */
682 if (view->screen->ignoreNextDoubleClick) {
683 view->screen->ignoreNextDoubleClick = 0;
684 } else {
685 if (event->type == ButtonPress) {
686 view->screen->lastClickWindow = event->xbutton.window;
687 view->screen->lastClickTime = event->xbutton.time;
691 W_ReleaseView(toplevel);
693 return True;
698 WMIsDoubleClick(XEvent *event)
700 W_View *view;
702 if (event->type != ButtonPress)
703 return False;
705 view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
707 if (!view)
708 return False;
710 if (view->screen->lastClickWindow != event->xbutton.window)
711 return False;
713 if (event->xbutton.time - view->screen->lastClickTime
714 < WINGsConfiguration.doubleClickDelay) {
715 view->screen->lastClickTime = 0;
716 view->screen->lastClickWindow = None;
717 view->screen->ignoreNextDoubleClick = 1;
718 return True;
719 } else
720 return False;
724 Bool
725 W_WaitForEvent(Display *dpy, unsigned long xeventmask)
727 #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
728 struct pollfd *fds;
729 InputHandler *handler;
730 int count, timeout, nfds, k, retval;
732 for (nfds = 1, handler = inputHandler;
733 handler != 0; handler = handler->next) nfds++;
735 fds = wmalloc(nfds * sizeof(struct pollfd));
736 fds[0].fd = ConnectionNumber(dpy);
737 fds[0].events = POLLIN;
739 for (k = 1, handler = inputHandler;
740 handler;
741 handler = handler->next, k++) {
742 fds[k].fd = handler->fd;
743 fds[k].events = 0;
744 if (handler->mask & WIReadMask)
745 fds[k].events |= POLLIN;
747 if (handler->mask & WIWriteMask)
748 fds[k].events |= POLLOUT;
750 #if 0 /* FIXME */
751 if (handler->mask & WIExceptMask)
752 FD_SET(handler->fd, &eset);
753 #endif
757 * Setup the select() timeout to the estimated time until the
758 * next timer expires.
760 if (timerPending()) {
761 struct timeval tv;
762 delayUntilNextTimerEvent(&tv);
763 timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
764 } else {
765 timeout = -1;
768 if (xeventmask==0) {
769 if (XPending(dpy))
770 return True;
771 } else {
772 XEvent ev;
773 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
774 XPutBackEvent(dpy, &ev);
775 return True;
779 count = poll(fds, nfds, timeout);
781 if (count > 0) {
782 handler = inputHandler;
783 k = 1;
784 while (handler) {
785 int mask;
786 InputHandler *next;
788 mask = 0;
790 if (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI))
791 mask |= WIReadMask;
793 if (fds[k].revents & (POLLOUT | POLLWRBAND))
794 mask |= WIWriteMask;
796 if (fds[k].revents & (POLLHUP | POLLNVAL | POLLERR))
797 mask |= WIExceptMask;
799 next = handler->next;
801 if (mask!=0 && handler->callback) {
802 (*handler->callback)(handler->fd, mask,
803 handler->clientData);
806 handler = next;
807 k++;
811 retval = fds[0].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI);
812 wfree(fds);
814 W_FlushASAPNotificationQueue();
816 return retval;
817 #else /* not HAVE_POLL */
818 #ifdef HAVE_SELECT
819 struct timeval timeout;
820 struct timeval *timeoutPtr;
821 fd_set rset, wset, eset;
822 int maxfd;
823 int count;
824 InputHandler *handler = inputHandler;
826 FD_ZERO(&rset);
827 FD_ZERO(&wset);
828 FD_ZERO(&eset);
830 FD_SET(ConnectionNumber(dpy), &rset);
831 maxfd = ConnectionNumber(dpy);
833 while (handler) {
834 if (handler->mask & WIReadMask)
835 FD_SET(handler->fd, &rset);
837 if (handler->mask & WIWriteMask)
838 FD_SET(handler->fd, &wset);
840 if (handler->mask & WIExceptMask)
841 FD_SET(handler->fd, &eset);
843 if (maxfd < handler->fd)
844 maxfd = handler->fd;
846 handler = handler->next;
851 * Setup the select() timeout to the estimated time until the
852 * next timer expires.
854 if (timerPending()) {
855 delayUntilNextTimerEvent(&timeout);
856 timeoutPtr = &timeout;
857 } else {
858 timeoutPtr = (struct timeval*)0;
861 XSync(dpy, False);
862 if (xeventmask==0) {
863 if (XPending(dpy))
864 return True;
865 } else {
866 XEvent ev;
867 if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
868 XPutBackEvent(dpy, &ev);
869 return True;
873 count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
875 if (count > 0) {
876 handler = inputHandler;
878 while (handler) {
879 int mask;
880 InputHandler *next;
882 mask = 0;
884 if (FD_ISSET(handler->fd, &rset))
885 mask |= WIReadMask;
887 if (FD_ISSET(handler->fd, &wset))
888 mask |= WIWriteMask;
890 if (FD_ISSET(handler->fd, &eset))
891 mask |= WIExceptMask;
893 next = handler->next;
895 if (mask!=0 && handler->callback) {
896 (*handler->callback)(handler->fd, mask,
897 handler->clientData);
900 handler = next;
904 W_FlushASAPNotificationQueue();
906 return FD_ISSET(ConnectionNumber(dpy), &rset);
907 #else /* not HAVE_SELECT, not HAVE_POLL */
908 Neither select nor poll. You lose.
909 #endif /* HAVE_SELECT */
910 #endif /* HAVE_POLL */
914 void
915 WMNextEvent(Display *dpy, XEvent *event)
917 /* Check any expired timers */
918 if (timerPending()) {
919 checkTimerHandlers();
922 while (XPending(dpy) == 0) {
923 /* Do idle stuff */
924 /* Do idle and timer stuff while there are no timer or X events */
925 while (!XPending(dpy) && idlePending()) {
926 if (idlePending())
927 checkIdleHandlers();
928 /* dispatch timer events */
929 if (timerPending())
930 checkTimerHandlers();
934 * Make sure that new events did not arrive while we were doing
935 * timer/idle stuff. Or we might block forever waiting for
936 * an event that already arrived.
938 /* wait to something happen */
939 W_WaitForEvent(dpy, 0);
941 /* Check any expired timers */
942 if (timerPending()) {
943 checkTimerHandlers();
947 XNextEvent(dpy, event);
950 #if 0
951 void
952 WMMaskEvent(Display *dpy, long mask, XEvent *event)
954 unsigned long milliseconds;
955 struct timeval timeout;
956 struct timeval *timeoutOrInfty;
957 fd_set readset;
959 while (!XCheckMaskEvent(dpy, mask, event)) {
960 /* Do idle stuff while there are no timer or X events */
961 while (idlePending()) {
962 checkIdleHandlers();
963 if (XCheckMaskEvent(dpy, mask, event))
964 return;
968 * Setup the select() timeout to the estimated time until the
969 * next timer expires.
971 if (timerPending()) {
972 delayUntilNextTimerEvent(&timeout);
973 timeoutOrInfty = &timeout;
974 } else {
975 timeoutOrInfty = (struct timeval*)0;
978 if (XCheckMaskEvent(dpy, mask, event))
979 return;
981 /* Wait for input on the X connection socket */
982 FD_ZERO(&readset);
983 FD_SET(ConnectionNumber(dpy), &readset);
984 select(1 + ConnectionNumber(dpy), &readset, (fd_set*)0, (fd_set*)0,
985 timeoutOrInfty);
987 /* Check any expired timers */
988 if (timerPending()) {
989 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 (idlePending()) {
1008 checkIdleHandlers();
1009 if (XCheckMaskEvent(dpy, mask, event))
1010 return;
1013 /* Wait for input on the X connection socket */
1014 W_WaitForEvent(dpy, mask);
1016 /* Check any expired timers */
1017 if (timerPending()) {
1018 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;